2015-04-03 1 views
0

Я немного смущен лучшим методом для этого. Я видел много примеров здесь, на SO, и многие ответы имеют разные решения. Поэтому я хотел бы узнать наиболее эффективный способ записи очень длинной строки в новый html-файл (т. Е. Сделать html-файл из строки). И действительно ли это нужно, чтобы все вставить в буфер? Как:Написание длинной строки в файл HTML, InputStream vs FileWriter vs BufferedReader

fileWriter = new FileWriter(new File(dir, appBook.getPath())); 
    bufferWritter = new BufferedWriter(fileWriter); 
    bufferWritter.append(htmlContent); 

или может я могу вместо этого сделать (без потери Performace)

fileWriter = new FileWriter(new File(dir, appBook.getPath())); 
    fileWriter .append(htmlContent); 

..

Это метод я использую на некоторое время теперь:

//Will run out of memory if i dont split the string in 650000 chunks 
    String[] bookPieces = splitString(htmlContent, Math.round(htmlContent.length()/650000)); 
    OutputStream outputStream = null; 
    InputStream inputStream = null; 

    try { 
     outputStream = new FileOutputStream(new File(dir, appBook.getPath())); //.html path 
     for (String text : bookPieces) { 
      byte[] theBytes = text.getBytes(Charset.forName("UTF-16")); 
      inputStream = new ByteArrayInputStream(theBytes); 
      byte[] bufferData = new byte[1024]; 
      int bytesRead = inputStream.read(bufferData); 

      while (bytesRead != -1) { 
       outputStream.write(bufferData, 0, bytesRead); //add the bufferData data to the "new file" 
       bytesRead = inputStream.read(bufferData); // keep on reading and filling the dynamic byte araay until it returns -1 
      } 
      //need to GC the inputsteam myself!!!! 
      inputStream = null; 

     } 
     toReturn = true; 

    } 

Чем я читал, то для использования длинных текстовых строк рекомендуется использовать BufferedReader. Таким образом, я изменил на:

String[] bookPieces = splitString(htmlContent, Math.round(htmlContent.length()/650000)); 
    OutputStream outputStream = null; 
    InputStream inputStream = null; 

    OutputStreamWriter oo; 

    try { 
     outputStream = new FileOutputStream(new File(dir, appBook.getPath())); 
     for (String text : bookPieces) { 

      byte[] theBytes = text.getBytes(Charset.forName("UTF-16")); 
      inputStream = new ByteArrayInputStream(theBytes); 

      InputStreamReader iReader = new InputStreamReader(inputStream,Charset.forName("UTF-16")); 
      BufferedReader bufferedReader = new BufferedReader(iReader); 

      oo = new OutputStreamWriter(outputStream); 

      String nextLine; 

      while ((nextLine = bufferedReader.readLine())!=null) { 
       oo.write(nextLine); 
      } 
      //need to GC the inputsteam myself!!!! 
      inputStream = null; 

     } 

Но я не могу получить право кодирования с этим методом, некоторые символы будут отличаться, как «-» становится «€». И я все еще должен разделить строку на куски, поэтому я не вижу цели изменить (я реализую это неправильно?), Пожалуйста, скажите мне правильный способ сделать это с помощью bufferedReader).

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

String[] bookPieces = splitString(htmlContent, Math.round(htmlContent.length()/100)); 
    FileWriter fileWriter = null; 
    BufferedWriter bufferWritter = null; 
    try { 
     fileWriter = new FileWriter(new File(dir, appBook.getPath())); 
     bufferWritter = new BufferedWriter(fileWriter); 

     //Has to append, if write than OOM. 
     bufferWritter.append(htmlContent); 

     toReturn = true; 

    } 

// И чем с кодировкой, которая slighltly медленнее, чем выше

//Need to split large strings in 100 chuncks 
    String[] bookPieces = splitString(htmlContent, Math.round(htmlContent.length()/100)); 
    BufferedWriter bufferWritter = null; 
    OutputStreamWriter osw= null; 
    try { 
     // Create osw and assign it an Encoding 
     osw = new OutputStreamWriter(
       new FileOutputStream(new File(dir, appBook.getPath())), 
       Charset.forName("UTF-16")); 
     bufferWritter = new BufferedWriter(osw); 
     for (String text : bookPieces) { 
      bufferWritter.write(text); //write faster than append here 
     } 

     toReturn = true; 

    } 
+0

'write()' не быстрее, чем 'append().' И вам не нужно GC входной поток [ваш] self '. Это локальная переменная, которая выходит из области действия при выходе из метода и автоматически будет GC'd. И обнуление ссылочных переменных не обязательно вызовет GC в любом случае. – EJP

+0

Просто читал ваш ответ на подобном протекте, помогал мне с чередованием строки :). Если я не сделаю inputStream null, я получу ошибку OOM: /, поэтому она должна задерживаться в куче где-нибудь (запускать ее на Android-телефоне, если это имеет значение). – user3711421

+0

Хм, я стоял исправлен, просто попробовал и установил нулевое значение, не имеет никакого значения. Прежде, хотя, это небольшое изменение остановило меня от ОМЕЮ по какой-то причине, должно быть, было чем-то еще. Однако, какой из этих методов был бы лучшим. Должен ли я использовать его в буфере или нет? – user3711421

ответ

1

Это простой, но более производительный способ, чтобы написать код, IMO:

int buffSize = Math.min(65536, htmlContent.length()); 
try (Writer osw = new OutputStreamWriter(
      new FileOutputStream(new File(dir, appBook.getPath())), 
      Charset.forName("UTF-16")); 
    BufferedWriter bw = new BufferedWriter(osw, buffSize)) { 
    bw.write(htmlContent); 
} 

Примечания по коду:

  1. Эта версия не разделяет текст. Код BufferedWriter.write(String) извлекает, преобразует и записывает строковые символы в кусках в зависимости от размера буфера BufferedWriter. Выполнение вашего собственного chunking является неуместным.

  2. Эта версия устанавливает размер буфера BufferedWriter в соответствии с размером записываемой строки. Но за пределами определенного размера (и предположительно 65K) вы не получаете никакого преимущества в производительности за счет увеличения размера буфера.

  3. В этой версии используется «попытка с ресурсами» для предотвращения утечки ресурсов.


Дальнейшие идеи.

Возможно использование более высокой производительности с использованием NIO.

Это может быть возможно получить еще более высокую производительность при использовании неприятной отражения для доступа массива private символов в String объекта. (Не делайте этого. Это НЕПРАВИЛЬНАЯ идея!)

Лучшим подходом может быть не сборка HTML как гигантской строки. Вместо этого напишите символы/строки, составляющие HTML, непосредственно на BufferedWriter. Это позволяет избежать необходимости хранить весь HTML в памяти за один раз .


1 - Предполагая, что вы используете StringBuilder без хорошего размера подсказки, вам потребуется до 3N символов из char[] собрать строку из размера N. Если у вас есть хороший размер намек, вам нужно только 2N chars ...

+0

Я не думаю, что понимаю ваши точки, хотя они, вероятно, хороши. Я не понимаю, как buffSize используется в вашем коде? И я извлекаю весь текст из webview (это htmlContent), чем я создаю новую веб-страницу с этим текстом. Попробуйте также с API req 19 :( – user3711421

+0

Исправленная ошибка. Посмотрите сейчас? Для материала, не связанного с chunking, вам нужно посмотреть исходный код 'BufferedWriter.write' ... и посмотреть, что он называет. –

+0

*« И i я извлекаю весь текст из webview (это htmlContent), чем я создаю новую веб-страницу с этим текстом ». * - Это не обязательно означает, что вы не можете передавать данные ... без буферизации всего этого как String. Это зависит от того, сколько усилий вы готовы потратить. –