JavaRush /Курсы /JAVA 25 SELF /Основные кодировки: UTF-8, UTF-16, ISO-8859-1

Основные кодировки: UTF-8, UTF-16, ISO-8859-1

JAVA 25 SELF
37 уровень , 1 лекция
Открыта

1. UTF-8 — король современных кодировок

В работе программиста вы столкнётесь с файлами, сетевыми протоколами, базами данных, веб‑сервисами, где используются разные кодировки. Если вы не знаете, чем UTF-8 отличается от ISO-8859-1, то легко попадёте в ловушку: ваш код будет работать «у меня на компьютере», но сломается у коллеги из Франции или в облаке, где другая система по умолчанию.

Сегодня мы разберём три основные кодировки, которые встречаются в реальной жизни Java‑разработчика:

  • UTF-8 — современный универсальный стандарт.
  • UTF-16 — внутренний формат строк в Java и часто встречается в Windows.
  • ISO-8859-1 (Latin-1) — старая, но до сих пор встречающаяся однобайтовая кодировка для западноевропейских языков.

Давайте познакомимся с ними поближе!

Что это такое?

UTF-8 (Unicode Transformation Format, 8-bit) — это кодировка, которая умеет представлять любой символ из огромной таблицы Unicode (а это и кириллица, и китайские иероглифы, и эмодзи, и даже редкие древние письменности). Причём делает это очень хитро: для самых популярных символов (английские буквы, цифры, знаки препинания) используется всего 1 байт. Для остальных — 2, 3 или даже 4 байта.

Факт: Все современные сайты, большинство JSON- и XML-файлов, и даже исходники на Java по умолчанию используют UTF-8.

Сколько нужно байт для одного символа?

  • ASCII‑символы (английские буквы, цифры, знаки препинания) — 1 байт.
  • Кириллические символы, европейские символы с диакритикой2 байта.
  • Китайские, японские, корейские иероглифы3 байта.
  • Супер‑экзотика, эмодзи4 байта.

Пример:

Символ Код в Unicode UTF-8 (в байтах)
A
U+0041
41
Я
U+042F
D0 AF
U+20AC
E2 82 AC
😀
U+1F600
F0 9F 98 80

Почему UTF-8 — это круто?

  • Обратно совместим с ASCII: если файл содержит только английские символы, он выглядит абсолютно так же, как в ASCII.
  • Компактность: для коротких текстов на английском языке файл в UTF-8 будет минимального размера.
  • Международность: поддерживает все языки мира, включая эмодзи.
  • Стандарт для web: HTML, CSS, JSON, XML, JavaScript — всё это по умолчанию UTF-8.

Пример использования в Java

import java.nio.charset.StandardCharsets;
import java.nio.file.*;

public class Utf8Demo {
    public static void main(String[] args) throws Exception {
        // Запись строки в файл в UTF-8
        String text = "Привет, мир! 😀";
        Files.write(Paths.get("utf8.txt"), text.getBytes(StandardCharsets.UTF_8));

        // Чтение файла в UTF-8
        String read = Files.readString(Paths.get("utf8.txt"), StandardCharsets.UTF_8);
        System.out.println(read); // Выведет: Привет, мир! 😀
    }
}

Здесь мы сначала явно кодируем строку в UTF-8 перед записью, а потом так же явно указываем кодировку при чтении. Благодаря этому текст сохраняется и восстанавливается без искажений, даже если в нём есть эмодзи или символы разных языков.

Когда использовать UTF-8?

Всегда, если только у вас нет очень веской причины выбрать что-то другое. Это универсальный выбор для всех современных приложений.

2. UTF-16 — внутренний формат Java

UTF-16 — это ещё одна кодировка из семейства Unicode. В отличие от UTF-8, она чаще всего использует 2 байта на символ. Именно так Java хранит строки (String) и символы (char) внутри JVM. Но есть нюанс: некоторые символы (например, редкие иероглифы или эмодзи) требуют уже 4 байта (две «суррогатные пары»).

Где используется UTF-16?

  • Внутри Java: все строки и символы — это UTF-16.
  • Windows: многие системные файлы в Windows используют UTF-16 (например, Notepad по умолчанию сохраняет в UTF-16 LE).
  • Некоторые сетевые протоколы и форматы: например, XML может быть в UTF-16.

Пример: как выглядит строка в UTF-16

Символ Код в Unicode UTF-16 (байты) Комментарий
A
U+0041
00 41
2 байта
Я
U+042F
04 2F
2 байта
U+20AC
20 AC
2 байта
😀
U+1F600
D8 3D DE 00
4 байта (суррогатная пара)

Пример использования в Java

import java.nio.charset.StandardCharsets;
import java.nio.file.*;

public class Utf16Demo {
    public static void main(String[] args) throws Exception {
        String text = "Привет, мир! 😀";

        // Запись строки в файл с использованием кодировки UTF-16
        Files.write(Paths.get("utf16.txt"), text.getBytes(StandardCharsets.UTF_16));

        // Чтение содержимого файла с указанием кодировки UTF-16
        String read = Files.readString(Paths.get("utf16.txt"), StandardCharsets.UTF_16);
        System.out.println(read); // Корректный вывод исходной строки
    }
}

Ключевой момент: при записи и чтении нужно указывать одну и ту же кодировку. Если записать в UTF-16, а прочитать по умолчанию (например, в UTF-8), возникнет «каша» из символов.

Особенности UTF-16

  • Фиксированная длина для большинства символов: 2 байта.
  • Суррогатные пары: часть символов (например, эмодзи) требуют 4 байта.
  • Byte Order Mark (BOM): в начале файла часто добавляется специальная «шапка», указывающая порядок байтов (LE — little endian, BE — big endian). Java обычно сама понимает BOM.
  • Не совместим с ASCII: если вы откроете UTF-16 файл в редакторе, который ждёт ASCII или UTF-8, увидите кучу нулей и странных знаков.

Когда использовать UTF-16?

  • Если вы работаете с очень специфичными системами или файлами, которые требуют именно UTF-16 (например, интеграция с Windows‑программами).
  • Для обычных приложений и файлов — лучше использовать UTF-8.

4. ISO-8859-1 (Latin-1) — привет из прошлого

ISO-8859-1, или Latin-1 — это однобайтовая кодировка, созданная ещё в далёкие 80‑е годы прошлого века. Она поддерживает 256 символов: английский алфавит, западноевропейские буквы с диакритикой (é, ü, ç и т.д.), знаки препинания, спецсимволы.

Факт: В этой кодировке нет кириллицы, греческих, арабских, китайских и других не‑латинских символов.

Где встречается ISO-8859-1?

  • В старых файлах и программах (особенно в Европе).
  • В некоторых базах данных и протоколах «по умолчанию».
  • В HTTP‑заголовках (по стандарту текстовые данные без указания кодировки считаются ISO-8859-1, хотя на практике это редко).

Пример: как выглядит строка в ISO-8859-1

Символ Код в Unicode ISO-8859-1 (байт) Комментарий
A
U+0041
41
То же, что в ASCII
é
U+00E9
E9
Французский
ü
U+00FC
FC
Немецкий
Я
U+042F
Нет такого символа!

Пример использования в Java

import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.charset.Charset;

public class Latin1Demo {
    public static void main(String[] args) throws Exception {
        String text = "Bonjour, ça va? Café!"; // Французский текст
        Files.write(Paths.get("latin1.txt"), text.getBytes(StandardCharsets.ISO_8859_1));

        // Чтение файла в ISO-8859-1
        String read = Files.readString(Paths.get("latin1.txt"), StandardCharsets.ISO_8859_1);
        System.out.println(read); // Всё читается корректно!

        // Попробуем записать кириллицу
        String cyrillic = "Привет, мир!";
        try {
            Files.write(Paths.get("badlatin1.txt"), cyrillic.getBytes(StandardCharsets.ISO_8859_1));
        } catch (Exception e) {
            System.out.println("Ошибка: невозможно записать кириллицу в ISO-8859-1!");
        }
    }
}

Кодировка ISO-8859-1 (Latin-1) поддерживает только западноевропейские символы — например, буквы с акцентами из французского, немецкого или испанского языков. Поэтому французский текст записывается и читается без проблем.

Однако кириллица в этой кодировке отсутствует, и при попытке её записать возникает ошибка или потеря символов. Именно поэтому для многоязычных текстов лучше использовать UTF-8 или UTF-16, которые охватывают гораздо больший набор символов.

Особенности ISO-8859-1

  • Ограничение по языкам: только западноевропейские языки.
  • 1 байт на символ: компактно, но очень ограниченно.
  • Запись «чужих» символов приводит к искажению: если попытаться сохранить кириллицу или иероглифы, они превратятся в вопросительные знаки или мусор.

Когда использовать ISO-8859-1?

  • Только если вы интегрируетесь с очень старой системой или базой данных, которая требует именно эту кодировку.
  • Для современных задач — не рекомендуется.

5. Полезные нюансы

Таблица сравнения кодировок

Кодировка Байт на символ Какие языки Совместимость с ASCII Где используется
UTF-8
1-4 Все Полная Web, Java, JSON, XML, Linux
UTF-16
2 или 4 Все Нет Внутри Java, Windows, XML
ISO-8859-1
1 Западная Европа Полная Старые программы, базы, HTTP

Как выбрать кодировку?

  • UTF-8 — ваш выбор для 99% задач. Совместим с ASCII, поддерживает все языки, минимальный размер для английского текста, стандарт для web и Java.
  • UTF-16 — используйте только если того требует спецификация или интеграция с Windows‑программами.
  • ISO-8859-1 — только для обратной совместимости со старыми системами. Никогда не используйте для хранения кириллицы, греческого, арабского и т.д.

Как узнать, в какой кодировке файл?

  • Откройте файл в редакторе, который показывает кодировку (например, Notepad++, VS Code).
  • Если видите «кракозябры», попробуйте открыть файл в другой кодировке.
  • В терминале Linux можно использовать команду file имя_файла — она иногда подсказывает кодировку.

Как задать кодировку в Java?

Используйте классы из пакета java.nio.charset:

  • StandardCharsets.UTF_8
  • StandardCharsets.UTF_16
  • StandardCharsets.ISO_8859_1

Или через имя кодировки:

Charset windows1251 = Charset.forName("Windows-1251");
Charset utf8 = Charset.forName("UTF-8");

6. Практика: что будет, если перепутать кодировку?

Давайте попробуем небольшой эксперимент. Запишем строку в UTF-8, а потом попробуем прочитать её как ISO-8859-1:

import java.nio.file.*;
import java.nio.charset.*;

public class EncodingMismatchDemo {
    public static void main(String[] args) throws Exception {
        String text = "Привет, мир!"; // Кириллица

        // Записываем как UTF-8
        Files.write(Paths.get("utf8demo.txt"), text.getBytes(StandardCharsets.UTF_8));

        // Читаем как ISO-8859-1 (НЕПРАВИЛЬНО!)
        String wrong = Files.readString(Paths.get("utf8demo.txt"), StandardCharsets.ISO_8859_1);
        System.out.println("Неправильное чтение: " + wrong);

        // Теперь читаем правильно
        String correct = Files.readString(Paths.get("utf8demo.txt"), StandardCharsets.UTF_8);
        System.out.println("Правильное чтение: " + correct);
    }
}

Результат:

  • В первом случае вы увидите «кракозябры» — набор странных символов.
  • Во втором случае — нормальный русский текст.

7. Типичные ошибки при работе с кодировками

Ошибка №1: Чтение файла в неверной кодировке. Если файл записан в UTF-8, а вы читаете его как ISO-8859-1 или Windows-1251, то все не‑ASCII символы превратятся в мусор. Это классика жанра: «у меня на компьютере всё работает, а у коллеги — нет».

Ошибка №2: Попытка записать «чужие» символы в однобайтовую кодировку. Если вы попытаетесь сохранить кириллицу или иероглифы в ISO-8859-1, Java заменит их на вопросительные знаки или выдаст ошибку. Данные будут потеряны безвозвратно.

Ошибка №3: Использование системной кодировки «по умолчанию». В некоторых методах Java (например, new FileReader("file.txt")) кодировка не указывается явно — используется системная. На одном компьютере это может быть UTF-8, на другом — Windows-1251, на третьем — вообще что-то экзотическое. Поэтому всегда используйте методы, где можно явно указать кодировку.

Ошибка №4: Открытие UTF-16 файла как UTF-8. Файл, записанный в UTF-16, если открыть как UTF-8, будет содержать кучу нулей и странных символов, потому что байты будут интерпретироваться неверно.

1
Задача
JAVA 25 SELF, 37 уровень, 1 лекция
Недоступна
Попытка отправить кириллицу через устаревшую систему связи 📟
Попытка отправить кириллицу через устаревшую систему связи 📟
1
Задача
JAVA 25 SELF, 37 уровень, 1 лекция
Недоступна
Лингвистический эксперимент: Вес слов в разных кодировках ⚖️
Лингвистический эксперимент: Вес слов в разных кодировках ⚖️
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Sergey Lunev Уровень 41
19 декабря 2025
Всем привет! У кого-то получилось сдать вторую задачу? Ругается на входящую строку из условий, всё остальное принимает