2016-08-05 118 views
0

我正在从套接字读取字节,然后使用jsonGenerator写入json文件。问题是JsonGenerator每次从套接字接收到一个流时都覆盖该文件。我如何使它追加后续的流而不是覆盖?JsonGenerator将json数据附加到文件而无需过度编写

JsonFactory factory = new JsonFactory(); 
     JsonGenerator generator = factory.createGenerator(
      new File("transactions.json"), JsonEncoding.UTF8); 

      try { 
     while ((bytesRead = in.read(bytes)) != -1){ // -1 indicates EOF 

      output= new String(bytes, "UTF-8"); 
      String length = output.substring(0, 4).trim(); 
      String mti = output.substring(4, 8).trim(); 
      String resp = "000"; 
      String newoutput = ""; 
      String bitmap = output.substring(8, 24); 
      String stan = output.substring(24, 30); 
      String date = output.substring(30, 44); 
      String function_code = output.substring(44, 47); 
      mti = "1814"; 


       // output to file 

      generator.writeStartObject(); 
      generator.writeStringField("MTI", mti); 
      generator.writeStringField("lenght", length); 
      generator.writeStringField("stan", stan); 
      generator.writeStringField("date", date); 
      generator.writeStringField("Function Code", function_code); 
       generator.writeEndObject(); 
      } 
    } catch (Exception e) { 
       System.out.println("Exceptions "+e); 
      }finally{ 
       generator.close(); 

      } 

此外,当我宣布发电机while循环外,并关闭外循环出于某种原因,数据不被写入文件,所以我还挺假设发电机喜欢它,当你关闭它写入缓冲区文件。

+0

如果你正在写多个对象,那么他们将是一个数组 –

+0

你知道你应该确保你阅读整个消息吗?在你呈现的这段代码中,它可能会读取一半的消息并尝试处理它,这可能会导致异常。你应该有一些协议,它从套接字读取inputStream的块,并且只处理整个块,而不是一半加载。 –

+0

如果你使用java 1.7,你应该在finally块中关闭generator,或者在“try-with-resources”中使用它。 –

回答

1

我可能会在你的问题中遗漏某些东西,但跳出来的覆盖原因是你没有指定该文件应该追加到。大多数Java API(包括Jackson)默认为覆盖而不是附加。简单的解决方法是只使用:

// the second parameter specifies whether the file should be appended 
try(OutputStream fos = new FileOutputStream(new File("transactions.json"), true)) { 

    // pass the FileOutputStream to the generator instead 
    JsonGenerator generator = factory.createGenerator(fos , JsonEncoding.UTF8); 
} 

我会留在这一点对我的答案,但我将是失职,如果我没有指出,如果你是从多个插座同时阅读,然后您可能最终会以JSON数据写入交错。

我建议将此方法包装在某种类型的同步块中,以防止出现这种情况并使其成为线程安全的。

下面我有一个如何重写这个功能的例子。

import com.fasterxml.jackson.core.JsonEncoding; 
import com.fasterxml.jackson.core.JsonFactory; 
import com.fasterxml.jackson.core.JsonGenerator; 

import java.io.File; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.nio.charset.StandardCharsets; 

/** 
* A thread-safe class that will append JSON transaction data to a file. 
*/ 
public class TransactionWriter { 
    private static final JsonFactory jsonFactory = new JsonFactory(); 

    /** 
    * Helper method that will read a number of UTF8 characters from an input stream and return them in a string. 
    * 
    * @param inputStream stream to read from 
    * @param charsToRead number of characters to read 
    * @return string of read characters 
    * @throws IOException when unable to read enough characters from the stream 
    */ 
    private static String readUtf8Chars(InputStream inputStream, int charsToRead) throws IOException { 
     // since we know this is UTF8 up front, we can assume one byte per char 
     byte[] buffer = new byte[charsToRead]; 

     // fill the buffer 
     int readBytes = inputStream.read(buffer); 

     // check that the buffer was actually filled 
     if(readBytes < charsToRead) 
      throw new IOException("less bytes available to read than expected: " + readBytes + " instead of " + charsToRead); 

     // create a string from the buffer 
     return new String(buffer, StandardCharsets.UTF_8); 
    } 


    private final File file; 
    private final Object writeLock = new Object(); 

    /** 
    * Constructs a new instance for an output file. 
    * 
    * @param file file to append to 
    */ 
    public TransactionWriter(File file) { 
     this.file = file; 
    } 

    /** 
    * Reads a transaction from the input stream and appends a JSON representation to this instance's output file. 
    * 
    * @param inputStream stream to read from; will be closed after this method is closed 
    * @throws IOException when reading or writing failed 
    */ 
    public void write(InputStream inputStream) throws IOException { 
     // since we have multiple threads appending to the same file, synchronize to prevent concurrency issues 
     synchronized(writeLock) { 

      // open the output stream to append to the file 
      try(FileOutputStream outputStream = new FileOutputStream(file, true)) { 

       // create the generator for the output stream 
       JsonGenerator generator = jsonFactory.createGenerator(outputStream, JsonEncoding.UTF8); 

       // write the data to the generator 
       generator.writeStartObject(); 
       generator.writeStringField("length", readUtf8Chars(inputStream, 4).trim()); 
       generator.writeStringField("MTI", readUtf8Chars(inputStream, 4).trim()); 
       String bitmap = readUtf8Chars(inputStream, 16); 
       generator.writeStringField("stan", readUtf8Chars(inputStream, 8)); 
       generator.writeStringField("date", readUtf8Chars(inputStream, 14)); 
       generator.writeStringField("Function Code", readUtf8Chars(inputStream, 3)); 
       generator.writeEndObject(); 

      } finally { 
       // output stream is closed in try-with-resources, but also close the input stream 
       inputStream.close(); 
      } 
     } 
    } 
} 

要清楚,我没有测试此代码在所有。我只知道它在Java 7语言级别编译。

+0

谢谢。让我试试你的选择。但我从一个套接字读取,也是唯一的,我没有把完整的代码放在这里,我使用线程时,一个流来一个新的线程产生执行然后杀死它。但我最终会用多线程服务器来完善它,我将拥有工作线程。现在我只想让逻辑正常工作。 –

0

在循环之外声明发生器(在循环之前)。

采取try-catch声明循环,有两种选择:

您应该关闭发电机(循环后),finally块,或者如果您使用java 1.7

用它,在“try-with-resources”的方式另外,你是否知道你应该确保你阅读完整的信息?在你呈现的这段代码中,它可能会读取一半的消息并尝试处理它,这可能会导致异常。您应该有一些协议从套接字读取inputStream的消息,并且只处理整个消息,而不是半载的块。 - Krzysztof Cichocki 2分钟前编辑

+0

我已经尝试过你的想法,但仍然无法正常工作,它不立即写入任何文件generator.close被取出循环 –

+0

发布新代码 –

+0

已发布新代码检查那里 –

相关问题