逐列写入CSV文件

时间:2012-09-23 23:09:14

标签: java csv

我正在寻找答案,但我找不到。有没有人有这种问题的解决方案。我有一组文本变量,我必须使用Java写入.CSV文件。我目前正在使用JavaScript调用Java。这是我现在能够很好地完成工作并将文本逐行写入.CSV的函数。

function writeFile(filename, data)
{
   try
   { 

      //write the data

      out = new java.io.BufferedWriter(new java.io.FileWriter(filename, true));
      out.newLine();
      out.write(data);
      out.close();
      out=null;
   }
   catch(e)   //catch and report any errors
   {
      alert(""+e);
   }
}

但是现在我必须逐个编写部分文本,如下面的示例。

first0,second0,third0
first1,second1,third1
first2,second2,third2
.
.
.
first9,second9,third9

所以算法是这样的。该函数用逗号写入first0然后转到下一行写入first1,转到下一行写入first2,然后写入first9。完成该部分之后,脚本将转到文件的开头并将second0写入逗号后面,转到下一行并将second1写入逗号后面,依此类推。你明白了。

所以现在我需要java

5 个答案:

答案 0 :(得分:3)

您可能需要考虑使用Super CSV来编写CSV文件。除了处理嵌入式双引号和逗号之外,它提供了一系列writing implementations,可以从数组/列表,地图甚至POJO中编写,这意味着您可以轻松地尝试自己的想法。

如果您想保持简单,可以将CSV文件组合成二维数组。这允许以列为先进行组装,然后在准备就绪时将整个内容写入CSV。

package example;

import java.io.FileWriter;
import java.io.IOException;

import org.supercsv.io.CsvListWriter;
import org.supercsv.io.ICsvListWriter;
import org.supercsv.prefs.CsvPreference;

public class ColumnFirst {

    public static void main(String[] args) {

        // you can assemble this 2D array however you want
        final String[][] csvMatrix = new String[3][3];
        csvMatrix[0][0] = "first0";
        csvMatrix[0][1] = "second0";
        csvMatrix[0][2] = "third0";
        csvMatrix[1][0] = "first1";
        csvMatrix[1][1] = "second1";
        csvMatrix[1][2] = "third1";
        csvMatrix[2][0] = "first2";
        csvMatrix[2][1] = "second2";
        csvMatrix[2][2] = "third2";

        writeCsv(csvMatrix);

    }

    private static void writeCsv(String[][] csvMatrix) {

        ICsvListWriter csvWriter = null;
        try {
            csvWriter = new CsvListWriter(new FileWriter("out.csv"), 
                CsvPreference.STANDARD_PREFERENCE);

            for (int i = 0; i < csvMatrix.length; i++) {
                csvWriter.write(csvMatrix[i]);
            }

        } catch (IOException e) {
            e.printStackTrace(); // TODO handle exception properly
        } finally {
            try {
                csvWriter.close();
            } catch (IOException e) {
            }
        }

    }

}

输出:

first0,second0,third0
first1,second1,third1
first2,second2,third2

答案 1 :(得分:1)

这是我解决问题的方法。由于低级随机访问文件机制,您不需要将整个数据保留在缓冲区。您仍然需要逐个加载记录:

package file.csv;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.List;

public class CsvColumnWriter {

    public static void main(String args[]) throws Exception{

        CsvColumnWriter csvWriter = new CsvColumnWriter(new File("d:\\csv.txt"), new File("d:\\csv.work.txt"), 3);

        csvWriter.writeNextCol(Arrays.asList(new String[]{"first0", "first1", "first2"}));
        csvWriter.writeNextCol(Arrays.asList(new String[]{"second0", "second1", "second2"}));
        csvWriter.writeNextCol(Arrays.asList(new String[]{"third0", "third1", "third2"}));

    }

    public void writeNextCol(List<String> colOfValues) throws IOException{
        // we are going to create a new target file so we have to first 
        // create a duplicated version
        copyFile(targetFile, workFile);

        this.targetStream = new BufferedOutputStream(new FileOutputStream(targetFile));

        int lineNo = 0;

        for(String nextColValue: colOfValues){

            String nextChunk = nextColValue + ",";

            // before we add the next chunk to the current line, 
            // we must retrieve the line from the duplicated file based on its the ofset and length 
            int lineOfset = findLineOfset(lineNo);  

            workRndAccFile.seek(lineOfset);

            int bytesToRead = lineInBytes[lineNo];
            byte[] curLineBytes = new byte[bytesToRead];
            workRndAccFile.read(curLineBytes);

            // now, we write the previous version of the line fetched from the
            // duplicated file plus the new chunk plus a 'new line' character
            targetStream.write(curLineBytes);
            targetStream.write(nextChunk.getBytes());
            targetStream.write("\n".getBytes());

            // update the length of the line
            lineInBytes[lineNo] += nextChunk.getBytes().length; 

            lineNo++;
        }

        // Though I have not done it myself but obviously some code should be added here to care for the cases where 
        // less column values have been provided in this method than the total number of lines

        targetStream.flush();
        workFile.delete();

        firstColWritten = true;
    }

    // finds the byte ofset of the given line in the duplicated file
    private int findLineOfset(int lineNo) {  
        int ofset = 0;
        for(int i = 0; i < lineNo; i++)
            ofset += lineInBytes[lineNo] + 
                (firstColWritten? 1:0); // 1 byte is added for '\n' if at least one column has been written
        return ofset;
    }

    // helper method for file copy operation
    public static void copyFile( File from, File to ) throws IOException {
            FileChannel in = new FileInputStream( from ).getChannel();
            FileChannel out = new FileOutputStream( to ).getChannel();
            out.transferFrom( in, 0, in.size() );
    }

    public CsvColumnWriter(File targetFile, File workFile, int lines) throws Exception{
        this.targetFile = targetFile;
        this.workFile = workFile;

        workFile.createNewFile();

        this.workRndAccFile = new RandomAccessFile(workFile, "rw");

        lineInBytes = new int[lines];
        for(int i = 0; i < lines; i++)
            lineInBytes[i] = 0;

        firstColWritten = false;
    }

    private File targetFile;
    private File workFile;

    private int[] lineInBytes;
    private OutputStream targetStream;
    private RandomAccessFile workRndAccFile;
    private boolean firstColWritten;

}

答案 2 :(得分:0)

我只是继续并假设你有一些自由来完成这项任务。据我所知,您不能将文本“插入”文件。您只能通过完全读取文件,在内存中更改它,然后将结果写回文件来完成。

因此,如果您在内存中反转数据结构然后编写它会更好。如果您的数据对象是一个矩阵,只需转置它,使其符合您要写的格式。

答案 3 :(得分:0)

这个怎么样

        Scanner input = new Scanner(System.in);
        String[] lines = new String[9];

        for (int j = 0; j < 2; j++) {
            for (int i = 0; i < 9; i++) {
                lines[i] += (String) input.nextLine() + ",";
            }
        }
        for (int i = 0; i < 9; i++) {
            lines[i] += (String) input.nextLine();
        }

答案 4 :(得分:0)

根据您在发生错误时不丢失任何数据的要求,也许您应该重新考虑设计并使用嵌入式数据库(在Embedded java databases处讨论了各种嵌入式数据库的优点)。您只需要在数据库中使用一个表。

我建议这样做,因为在您的原始问题中,您似乎正在尝试使用CSV文件,如数据库,您可以按任意顺序更新任何行的列。在这种情况下,为什么不咬紧牙关并使用真正的数据库。

无论如何,一旦填写了表的所有列和行,就将数据库导出为“文本文件顺序”中的CSV文件row1-col1,row1-col2 ... row2-col1等。

如果在构建数据库期间发生错误,或者至少导出CSV文件,您仍然可以获得上一次运行的所有数据,并且可以再试一次。