#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. Я могу подтвердить, что это работает