Java scanner.nextLine() не читает длинную строку с 259094 символами

#java #java.util.scanner

#java #java.util.scanner

Вопрос:

Я хочу прочитать XML-файл в виде строки на Java, чтобы я мог его зашифровать.

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

Моя проблема заключается в том, что третья строка в XML-файле имеет длину 259094 символа, и по какой-то причине метод nextLine() сканера считывает только до 131072 символов в строку вместо целой строки. Мой код для чтения XML-файла приведен ниже, и это XML-файл, который я использовал.

 try {
  File myFile = new File(filename);
  Scanner myReader = new Scanner(myFile);
  int lineCount = 0;

  while (myReader.hasNextLine()) {
    if (lineCount > 0) { // To make sure it doesn't append n before the first line[enter link description here][1]
      data  = "n";
    }
    String temp = myReader.nextLine();
    data  = temp;
    lineCount  = 1;
  }
      
  myReader.close();
}
catch (FileNotFoundException e) {
  System.out.println("An error occurred.");
  e.printStackTrace();
}
 

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

1. При сохранении в XML-файле были удалены пробелы. (Возврат каретки в содержимом после объявлений xml и Microsoft в строках 0 и 1 отсутствует). Так что, да … Эта одна строка, содержащая все содержимое xml, взорвет ваш сканер. Вам нужно будет загрузить это с помощью потока и зашифровать его по частям.

2. Я успешно прочитал файл. Третья строка содержит 259094 символа. Произошла ли какая-либо ошибка или третья строка содержит пробел после 131072 символов?

3. Разве не разумно просто читать из входного потока (из чего бы он ни исходил, скажем, из вашего XML-файла) и записывать в зашифрованный выходной поток (куда бы он ни направлялся)?

4. То, что написал fluffy, решит другую проблему: поддерживается много «добрых» разделителей строк Scanner.nexLine() (взглянув на исходный код, я вижу регулярное выражение, подобное rn|[nru2028u2029u0085] , так что в общей сложности 6 разных разделителей строк). Вы заменяете их все n созданием «другого файла», который затем хешируете.

5. Зачем использовать сканер (который в основном существует для анализа входных данных), чтобы сделать что-то столь же простое, как чтение всего файла (который не требует синтаксического анализа)?

Ответ №1:

Предоставленный вами код отлично работает в моей системе.

Но если ваша цель — зашифровать файл (без его синтаксического анализа), то нет причин, по которым вы должны читать его как строку. Вы могли бы просто обработать его как поток байтов и зашифровать их.

Примером для этого может быть следующий код:

     public static void main(String[] args) throws NoSuchAlgorithmException {
            String filename = "/tmp/xml.xml";
    
            KeyGenerator keygen = KeyGenerator.getInstance("AES");
            keygen.init(256);
            SecretKey secretKey = keygen.generateKey();
            byte[] IV = new byte[16]; //TODO The bytes should be random and different for each file
            GCMParameterSpec gcmSpec = new GCMParameterSpec(128, IV);
    
            try {
                encryptFile(new File(filename), new File(filename   ".encrypted"), secretKey, gcmSpec);
                decyptFile(new File(filename   ".encrypted"), new File(filename   ".decrypted"), secretKey, gcmSpec);
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
    
        }
    
        static void encryptFile(File inputFile, File outputFile, SecretKey secretKey, GCMParameterSpec gcmSpec) throws InvalidKeyException, IOException {
            InputStream input = null;
            OutputStream output = null;
            try {
                input = new BufferedInputStream(new FileInputStream(inputFile));
                output = new BufferedOutputStream(new FileOutputStream(outputFile));
                Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5Padding");
    
                cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmSpec);
    
                while (input.available() > 0) {
                    byte[] bytes = input.readNBytes(128);
                    output.write(cipher.update(bytes));
                }
                output.write(cipher.doFinal());
    
            } catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
                e.printStackTrace();
                System.exit(1);
            } finally {
                if (input != null) input.close();
                if (output != null) output.close();
            }
        }
    
        static void decyptFile(File encryptedFile, File outputFile, SecretKey secretKey, GCMParameterSpec gcmSpec) throws InvalidKeyException, IOException {
            InputStream input = null;
            OutputStream output = null;
            try {
                input = new BufferedInputStream(new FileInputStream(encryptedFile));
                output = new BufferedOutputStream(new FileOutputStream(outputFile));
                Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5Padding");
    
                cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmSpec);
    
                while (input.available() > 0) {
                    byte[] bytes = input.readNBytes(128);
                    output.write(cipher.update(bytes));
                }
    
                output.write(cipher.doFinal());
    
            } catch (NoSuchPaddingException | NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | InvalidAlgorithmParameterException e) {
                e.printStackTrace();
            } finally {
                if (input != null) input.close();
                if (output != null) output.close();
            }
        }
 

Это считывает файл и сохраняет выходные данные в другой файл. Обратите внимание, что для обеспечения безопасности вам необходимо изменить IV на случайное значение с изменениями для каждого файла (возможно, путем сохранения iv в начале зашифрованного файла)

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

1. Спасибо, я рассмотрю ваш второй пункт. Тем не менее, я четко привел пример файла со ссылкой на Google Диск. Может быть, прочтите весь мой вопрос, прежде чем отвечать / голосовать против?

2. Извините, я не видел файл примера.

3. не беспокойтесь, я прочитал некоторые комментарии выше, и код, похоже, отлично работает и в некоторых других системах. у некоторых других парней также было подобное предложение, и я обязательно попробую его, когда вернусь. большое спасибо 🙂

4. спасибо piliko здесь и всем, кто рекомендовал аналогичное решение с использованием InputStream. Я могу подтвердить, что это работает