csv

CSV文件流操作

csv内容格式就是纯文本的字符拼接,本质上是获取特殊字符串分割的字符串,将字符串转换为文件流

分隔符

  1. 列分隔符,如|等
  2. 行分隔符,需要根据操作系统区分
    1. Unix系统里,每行结尾只有“<换行>”,即“\n”;
    2. Windows系统里面,每行结尾是“<回车><换行>”,即“\r\n”;
    3. Mac系统里,每行结尾是“<回车>”,即“\r”。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
List<List<String>> dataList = new ArrayList<>();
dataList.add(Arrays.asList("a", "b", "c", "d", "e", "f", "z"););
dataList.add(Arrays.asList("a", "b", "c", "d", "e", "f", "z"););
dataList.add(Arrays.asList("a", "b", "c", "d", "e", "f", "z"););


// 拼接成字符串
List<String> rowList = new ArrayList<>();
for (List<String> row : dataList) {
String rowStr = String.join("|", row);
rowList.add(rowStr);
}
String rowsStr = String.join("\n", rowList);

// 将字符串转换为文件流
byte[] bytes = rowsStr.getBytes(StandardCharsets.UTF_8);
InputStream file = new ByteArrayInputStream(bytes);
// bytes.length可以获得文件的字节大小。
// InputStream文件流可以和File进行转换。

文件流API详解

  1. 所有的 io操作都保存在 java.io包中
  2. 在整个 io包中,唯一表示与文件本身有关的类就是File
  3. 所有程序数据都是的方式传输或保存。【流中保存的全都是字节文件】
    • 程序需要数据时,使用输入流读取数据
    • 程序需要将数据保存起来的时候,使用输出流
文件流分类
graph LR
A(IO) --> B(字节流)
A-->C(字符流)

B --> B1(输入)
B1 -.- InputStream(InputStream)
B --> B2(输出)
B2 -.- OutputStream(OutputStream)

C --> C1(输入)
C1 -.- Reader(Reader)
C--> C2(输出)
C2 -.- Writer(Writer)
文件流区分
  1. 字节流:直接操作文件。不会用到缓冲区(内存)。
    • 在①硬盘上保存文件,或是②传输时,都以字节方式进行。图片也是按字节完成。【使用最多】
    • 字节流操作 byte类型数据,几乎所有数据都可以直接使用 byte数组表示。
  2. 字符流:不能直接操作文件,需要用到缓存。先将数据放到缓存中,再从缓存写入文件。
    • 字符是只有在内存中才会形成。
graph LR
A(程序) --> B(字节流)
B--> C>文件]

A1(程序) --> B1(字符流)
B1 --> C1(缓存)
C1--> D1>文件]
字节流InputStream
  1. 通过 InputStream可以从文件中把内容读取进来
  2. InputStream本身也是一个抽象类,必须依靠其子类,如果现在是从文件中读取,子类是 FileInputStream
  3. 获取文件大小:直接使用 File类即可:public long length()
graph LR
InputStream --> I1(ByteArrayInputStream)
InputStream --> I2(FileInputStream)
InputStream --> I3(ObjectInputStream)
InputStream --> I4(PipedInputStream)
InputStream --> FilterInputStream(FilterInputStream)
InputStream --> I6(SequenceInputStream)

FilterInputStream --> DataInputStream(DataInputStream)
FilterInputStream --> BufferedInputStream(BufferedInputStream)
FilterInputStream --> PushbackInputStream(PushbackInputStream)
字节流OutputStream
  1. OutputStream是一个抽象类,如果要想使用此类的话,则首先必须子类实例化对象,那么如果现在要操作的是一个文件,则可以使用:FileOutputStream类,通过向上转型之后,可以为 OutputStream实例化
  2. Closeable:表示可以关闭的操作,因为程序运行到最后肯定要关闭
  3. Flushable:表示刷新,清空内存中的数据
graph LR
OutputStream --> O1(ByteArrayOutputStream)
OutputStream --> O2(FileOutputStream)
OutputStream --> O3(ObjectOutputStream)

OutputStream --> FilterOutputStream(FilterOutputStream)
OutputStream --> O5(PipedOutputStream)

FilterOutputStream --> DataOutputStream(DataOutputStream)
FilterOutputStream --> BufferedOutputStream(BufferedOutputStream)
FilterOutputStream --> PrintOutputStream(PrintOutputStream)
字符流

在程序中一个字符等于2个字节,JAVA提供了Reader、Writer两个专门操作字符流的类

Writer

  1. Writer抽象类,如果是向文件中写入内容,所以应该使用 FileWriter的子类
  2. 字符流的操作比字节流操作的优点:可以直接输出字符串,不用进行转换

Reader

  1. Reader抽象类,使用字符的方式从文件取出数据,如果现在要从文件中读取内容,则可以直接使用 FileReader子类

CSV文件编码

在JAVA下输出文件流,保存成CSV(用UTF-8)文件。用EXCEL打开是乱码,用记事本等其他软件正常且显示是UTF-8的编码。

这是EXCEL本身的问题,不是CSV文件的问题。

1、EXCEL只能打开ANSI的编码,而ANSI需要当前操作系统是什么编码,就用什么编码。如中文系统下,则只能认识GBK的编码,不认识UTF-8的编码,唯一的解决办法就是将文件流输出成GBK等当前操作系统认识的编码。

可以通过Properties properties = System.getProperties();
String encodingStr = properties.getProperty(“file.encoding”);
来查看当前的服务器下的编码是什么,如果服/客编码不一致,如服务器是UTF-8,而客户端是GBK,则想要CSV不乱码,唯一的解决办法是将输出的内容通过outTmp.toString().getBytes(“GBK”)强制转化成客户端支持的GBK。

-------------Keep It Simple Stupid-------------
0%