Как стать автором
Поиск
Написать публикацию
Обновить
524.83
OTUS
Развиваем технологии, обучая их создателей

Хотите писать без ошибок? Узнайте, как Java обрабатывает кодировки

Время на прочтение5 мин
Количество просмотров1.3K

Автор статьи: Сергей Прощаев (@sproshchaev), Руководитель направления Java‑разработки в FinTech

Введение

Многие наверняка сталкивались с ситуацией, когда при открытии файла в текстовом редакторе (например, Word) вместо ожидаемого текста появляется хаотичный набор символов: или «кракозябры». Такое происходит, когда программа неправильно определяет кодировку файла — набор правил, по которым символы преобразуются в двоичный код.

Каждый формат файла (TXT, DOCX, PDF и другие) имеет свою структуру и использует определённую кодировку для хранения данных. Если приложение неверно интерпретирует эти правила, текст становится нечитаемым.

Кодировки или как компьютеры понимают наш язык?

Когда вы печатаете сообщение или читаете статью в интернете, ваш компьютер видит не буквы, а комбинации нулей и единиц. Чтобы превратить эти биты в понятный текст, нужны таблицы кодировок — своего рода «переводчики» между человеческим языком и машинным кодом.

Представьте, что компьютер — это иностранец, который понимает только цифры. Чтобы объяснить ему, что означает буква «А» или символ «!», нужен словарь. Таблица кодировки как раз и является таким словарем: она сопоставляет каждому символу (букве, цифре, эмодзи) уникальный числовой код. Этот код затем преобразуется в байты — минимальные единицы данных, которые компьютер может хранить или передать.

Процесс кодирования состоит из двух шагов.

На первом шаге кодирования символ преобразуется в числовой код. Например, в кодировке ASCII (American Standard Code for Information Interchange) буква A имеет код 65.

Почему 65? Давайте разберемся. В основе этого преобразования лежит система счисления с основанием числа 2 или двоичная система.

Рис. 1 Преобразование буквы A в число 65
Рис. 1 Преобразование буквы A в число 65

Каждая ячейка на рис.1 — это «бит» (0 или 1). Биты соответствуют степеням числа 2: 64 = 2⁶, 32 = 2⁵, 16 = 2⁴, 8 = 2³, 4 = 2², 2 = 2¹, 1 = 2⁰. Как читать двоичное число? Если под числом стоит 1 — оно включено в сумму, если 0 — исключено. На слайде: 64 (2⁶) = 1 → берём 64 32, 16, 8, 4, 2 = 0 → не берём 1 (2⁰) = 1 → берём 1. Теперь складываем выбранные числа: 64 + 1 = 65.

На втором шаге кодирования код 65 преобразуется в последовательность байтов. В ASCII буква A становится байтом 1 000 001. На рис.1 это цифры 1 и 0 красного цвета.

И теперь эти семь бит 1 000 001 мы можем поместить в специальную таблицу, которую называют таблицей кодировок.

Таблицы кодировок

Таблиц кодировок было изобретено множество. Таблица ASCII (American Standard Code for Information Interchange), представленная на рис.2, была создана в 1960-х годах и изначально предназначалась для англоязычных пользователей.

Рис. 2 Таблица ASCII
Рис. 2 Таблица ASCII

ASCII использует 7 бит данных, что позволяет закодировать всего 128 символов — этого хватает для английского алфавита (заглавные и строчные буквы), цифр, знаков препинания и управляющих команд (например, «перевод строки»). И как раз наша английская буква A, закодированная как 1 000 001 может быть помещена в эту таблицу.

Как в Java можно прочитать и записать произвольную строку символов в файл?

Допустим, мы хотим сохранить фразу «Hello, World!» в файл. Вот как это можно сделать:

import java.io.*;

public class WriteFileDefaultEncoding {
    public static void main(String[] args) {
        String text = "Hello, World!";

        try (Writer writer = new BufferedWriter(
                new FileWriter("default_file.txt"))) {
            writer.write(text);
            System.out.println("Файл записан с кодировкой по умолчанию.");
        } catch (IOException e) {
          System.out.println("Ошибка: " + e.getMessage());
        }
    }
}

Как это работает все вместе? FileReader открывает файл default_file.txt и пытается прочитать его в кодировке системы. BufferedReader считывает данные блоками (в данном примере — по 1024 символа за раз). StringBuilder собирает все считанные части в одну строку, а try‑with‑resources автоматически закрывает поток после чтения, даже если произошла ошибка.

В этом примере используются классы из пакета java.io. Класс FileWriter записывает текст в файл, используя кодировку по умолчанию. Класс BufferedWriter оборачивает FileWriter для буферизации данных. Использование буферизации увеличивает скорость записи, так как данные сначала накапливаются в памяти (буфере), а затем записываются в файл большими порциями. Writer представляет собой абстрактный класс, который является базовым для всех классов, записывающих символы в поток. Если произойдёт ошибка (например, файл заблокирован другим процессом), будет выброшено исключение IOException, и программа выведет сообщение об ошибке.

Теперь выполним обратную операцию и прочитаем файл default_file.txt, созданный в предыдущем примере, и отобразим его содержимое в консоль:

import java.io.*;

public class ReadFileDefaultEncoding {
    public static void main(String[] args) {
        try (Reader reader = new BufferedReader(
                new FileReader("default_file.txt"))) {
            char[] buffer = new char[1024];
            int length;
            StringBuilder content = new StringBuilder();
            while ((length = reader.read(buffer)) != -1) {
                content.append(buffer, 0, length);
            }
            System.out.println("Содержимое файла: " + content.toString());
        } catch (IOException e) {
            System.out.println("Ошибка: " + e.getMessage());
        }
    }
}

FileReader открывает файл default_file.txt и пытается прочитать его в кодировке системы. BufferedReader считывает данные блоками (в данном примере — по 1024 символа за раз). StringBuilder собирает все считанные части в одну строку.

Какие классы используются здесь? FileReader читает текст из файла, используя кодировку по умолчанию. BufferedReader оборачивает FileReader для буферизации данных. Данные, при использовании BufferedReader считываются большими блоками, а не по одному символу. Reader это абстрактный класс, базовый для всех классов, считывающих символы из потока.

Заключение

Понимание кодировок — основа работы с текстом в Java и любом другом языке программирования. Кодировки определяют, как символы (буквы, цифры, знаки) преобразуются в двоичный код, который понимает компьютер. Без этого знания даже простые операции — например, чтение файла или вывод строки на экран — могут привести к ошибкам.


Если вы хотите углубить свои знания в области работы с данными, оптимизации процессов или улучшения архитектуры приложений, обратите внимание на следующие открытые онлайн-уроки. Они помогут разобраться в актуальных аспектах технологий и понять, как они применяются в реальных проектах:

Больше актуальных навыков по разработке и работе с данными вы можете получить в рамках практических онлайн-курсов от экспертов отрасли.

Теги:
Хабы:
Всего голосов 12: ↑6 и ↓6+2
Комментарии5

Публикации

Информация

Сайт
otus.ru
Дата регистрации
Дата основания
Численность
101–200 человек
Местоположение
Россия
Представитель
OTUS