JsonGenerator将json数据附加到文件而没有过多的写入

时间:2016-08-05 08:20:37

标签: java json sockets jackson

我正从套接字读取字节,然后使用jsonGenerator写入json文件。问题是JsonGenerator每次从套接字接收流时都会覆盖该文件。如何使其附加后续流而不是覆盖?

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循环之外声明生成器并在循环之外将它关闭时由于某种原因数据没有写入文件所以我假设生成器有点像缓冲它,当你关闭它时写入文件。

2 个答案:

答案 0 :(得分: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语言级别上编译。

答案 1 :(得分:0)

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

try-catch语句中进行循环,有两个选项:

如果使用try-with-resources

此外,您是否知道应该确保阅读整条信息?在您提供的此代码中,它可以读取一半消息并尝试处理它,这可能会导致异常。您应该有一些协议从套接字读取java 1.7的消息,并且只处理整个消息,而不处理半载的块。 - Krzysztof Cichocki 2分钟前编辑