Метод readChar() отображает японские символы

#java #randomaccessfile

#java #randomaccessfile

Вопрос:

Я пытаюсь написать код, который выбирает слово из файла в соответствии с индексом, введенным пользователем, но проблема в том, что метод readChar() из RandomAccessFile класса возвращает японские символы, я должен признать, что это не первый раз, когда я видел это на своем ноутбуке Lenovo, иногдав некоторых мастерах установки я вижу смешанный материал с обычными символами, смешанными с японскими символами, как вы думаете, это происходит с ноутбука или, скорее, из кода?

Это код:

 package com.project;

import java.io.*;
import java.util.StringTokenizer;

public class Main {

    public static void main(String[] args) throws IOException {
        int N, i=0;
        char C;
        char[] charArray = new char[100];
        String fileLocation = "file.txt";
        BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
        do {
            System.out.println("enter the index of the word");
            N = Integer.parseInt(buffer.readLine());
            if (N!=0) {
                RandomAccessFile word = new RandomAccessFile(new File(fileLocation), "r");
                do {
                    word.seek((2*(N-1)) i);
                    C = word.readChar();
                    charArray[i] = C;
                    i  ;
                }while(charArray[i-1] != ' ');
                System.out.println("the word of index "   N   " is: " );
                for (char carTemp : charArray )
                System.out.print(carTemp);
                System.out.print("n");

            }
        }while(N!=0);
        buffer.close();
    }
}
  

я получаю этот вывод :

 瑯潕啰灰灥敲牃䍡慳獥攨⠩⤍ഊੴ瑯潌䱯潷睥敲牃䍡慳獥攨⠩⤍ഊ੣捯潭浣捡慴琨⡓却瑲物楮湧朩⤍ഊ੣捨桡慲牁䅴琨⡩楮湴琩⤍ഊੳ獵畢扳獴瑲物楮湧木⠠⁳獴瑡慲牴琠⁩楮湤摥數砬Ⱐ⁥敮湤搠⁩楮湤摥數砩⤍ഊੴ瑲物業洨⠩Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 100 out of bounds for length 100
    at Main.main(Main.java:21)
  

Комментарии:

1. Возможно, это как-то связано с кодировкой? (незначительная ошибка — вы написали "/n" вместо "n" или просто System.out.println() ) Не могли бы вы попробовать распечатать их как целые числа, а не как символы?

2. Что вы вычисляете в качестве параметра поиска?

3. Что находится в файле, который вы читаете? Как это кодируется? Если это юникод, возможно, ваш поиск приводит вас к середине символа. Что вы думаете о том, что word.seek((2*(N-1)) i); делает? Я не понимаю, как это приведет вас к границе слова.

4. Кроме того, ваша логика для определения того, когда прекратить чтение, кажется ошибочной. Строка charArray[i ] = C; помещает следующий символ в буфер, но затем перемещает ‘i’ в местоположение после этого, поэтому строка while(charArray[i] != ' ') проверяет не только прочитанный символ, но и все, что находится в буфере, перед записью следующего символа в это местоположение.

5. я исправил проблемы, на которые вы указали, но все то же самое, с помощью (2 * (N-1)) i я читаю (два байта), которые соответствуют символу, затем я увеличиваю на 1, чтобы прочитать следующий символ, пока не дойду до пробела

Ответ №1:

Есть много неправильных вещей, все из которых связаны с фундаментальными заблуждениями.

Прежде всего: файл на вашем диске — не говоря уже об File интерфейсе на Java или любом другом языке программирования; сам файл — не содержит и не может хранить текст. Когда-либо. Он хранит байты. То есть необработанные данные, как (на каждой машине, которая была актуальна десятилетиями, но исторически существовали и другие способы сделать это), выраженные в битах, которые организованы в группы по 8, называемые байтами.

Текст — это абстракция; интерпретация некоторой конкретной последовательности байтовых значений. Это зависит — фундаментально и неизбежно — от кодировки. Поскольку это не блог, я избавлю вас от урока истории здесь, но достаточно сказать, что char тип Java не просто хранит символ текста. Он хранит двухбайтовое значение без знака, которое может представлять символ текста. Поскольку в Юникоде больше символов текста, чем могут представлять два байта, иногда char для представления символа текста требуются два соседних s в массиве. (И, конечно, вероятно, существует код, который злоупотребляет char типом просто потому, что кто-то хотел получить беззнаковый эквивалент short . Возможно, я даже написал некоторые из них сам. Эта эпоха для меня размыта.)

В любом случае, суть в том, что using .readChar() будет считывать два байта из вашего файла и сохранять их в a char внутри вашего char[] , и соответствующее числовое значение не будет похоже на то, которое вы хотели, — если только ваш файл не будет закодирован с использованием той же кодировки, которую Java использует изначально, называемой UTF-16.

Вы не сможете правильно прочитать и интерпретировать файл, не зная кодировку файла. Полная остановка. В лучшем случае вы можете обманывать себя, полагая, что можете его прочитать. У вас также не может быть «произвольного доступа» к текстовому файлу, то есть индексации в соответствии с количеством символов текста, если только рассматриваемая кодировка не имеет постоянной ширины. (В противном случае, конечно, вы не можете просто вычислить расстояние в байтах до файла, в котором находится данный символ текста; это зависит от того, сколько байтов заняли предыдущие символы, что зависит от того, какие символы они.) Многие текстовые кодировки не имеют постоянной ширины. Один из самых популярных, который, честно говоря, является разумной рекомендацией по умолчанию для большинства задач в наши дни, не является. В этом случае вам просто не повезло с проблемой, которую вы описываете.

В любом случае, как только вы узнаете кодировку вашего файла, ожидаемый способ извлечения символа текста из файла на Java — использовать один из классов Reader, такой как InputStreamReader:

InputStreamReader — это мост от потоков байтов к потокам символов: он считывает байты и декодирует их в символы, используя указанную кодировку. Кодировка, которую он использует, может быть указана по имени или может быть задана явно, или может быть принята кодировка платформы по умолчанию.

(Здесь charset просто означает экземпляр класса, который Java использует для представления текстовых кодировок.)

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

Комментарии:

1. да, с UTF-16 я начал получать узнаваемый символ, спасибо.

Ответ №2:

char составляет 16 бит, то есть 2 байта.

seek ищет границу байта.

Если файл содержит символы, то они имеют четные смещения: 0, 2, 4…

Выражение (2*(N-1)) i) четное i , если оно четное; если нечетное, вы обязательно попадете в середину символа и, таким образом, прочитаете мусор.

i начинается с нуля, но вы увеличиваете на 1, то есть на половину символа.

Ваш аргумент seek, вероятно, должен быть (2*(N-1 i)) .


Альтернативное объяснение: ваш файл вообще не содержит chars ; например, вы создали файл ASCII, в котором символ представляет собой один байт.

В этом случае ошибка заключается в попытке прочитать ASCII (устаревшую кодировку символов) с readChar помощью функции.

Но если файл содержит ASCII, цель умножения на 2 в аргументе поиска неясна. По-видимому, он не служит никакой полезной цели.

Комментарии:

1. Да, это то, что я хотел сделать 2 * (N-1 i), спасибо

Ответ №3:

Я изменил кодировку файла на UTF-16 и модифицировал программу, чтобы отображать правильные индексы, те, которые представляют начало каждого слова, теперь все работает нормально, спасибо, ребята.

   import java.io.*;

public class Main {
public static void main(String[] args) throws IOException {
    int N, i=0, j=0, k=0;
    char C;
    char[] charArray = new char[100];
    String fileLocation = "file.txt";
    BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
    DataInputStream in = new DataInputStream(new FileInputStream(fileLocation));
    boolean EOF=false;
    do {
        try {
            j  ;
            C = in.readChar();
           if((C==' ')||(C=='n')){
                System.out.print(j 1 "t");
            }

        }catch (IOException e){
            EOF=true;
        }

    }while (EOF!=true);
    System.out.println("n");
    do {
        System.out.println("enter the index of the word");
        N = Integer.parseInt(buffer.readLine());
        if (N!=0) {
            RandomAccessFile word = new RandomAccessFile(new File(fileLocation), "r");


            do {

                word.seek((2*(N-1 i)));
                C = word.readChar();
                charArray[i] = C;
                i  ;
            }while(charArray[i-1] != ' ' amp;amp; charArray[i-1] != 'n');
            System.out.print("the word of index "   N   " is: " );
            for (char carTemp : charArray )
                System.out.print(carTemp);
            System.out.print("n");
             i=0;
            charArray = new char[100];
        }
    }while(N!=0);
    buffer.close();


   }
}