CSV文件流操作
csv内容格式就是纯文本的字符拼接,本质上是获取特殊字符串分割的字符串,将字符串转换为文件流。
分隔符
- 列分隔符,如|等
- 行分隔符,需要根据操作系统区分
- Unix系统里,每行结尾只有“<换行>”,即“\n”;
- Windows系统里面,每行结尾是“<回车><换行>”,即“\r\n”;
- Mac系统里,每行结尾是“<回车>”,即“\r”。
代码示例
1 | List<List<String>> dataList = new ArrayList<>(); |
文件流API详解
- 所有的 io操作都保存在 java.io包中
- 在整个 io包中,唯一表示与文件本身有关的类就是
File
类 - 所有程序数据都是
流
的方式传输或保存。【流中保存的全都是字节文件】- 程序需要数据时,使用输入流读取数据
- 程序需要将数据保存起来的时候,使用输出流
文件流分类
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)
文件流区分
- 字节流:直接操作文件。不会用到缓冲区(内存)。
- 在①硬盘上保存文件,或是②传输时,都以字节方式进行。图片也是按字节完成。【使用最多】
- 字节流操作
byte
类型数据,几乎所有数据都可以直接使用byte数组
表示。
- 字符流:不能直接操作文件,需要用到缓存。先将数据放到缓存中,再从缓存写入文件。
- 字符是只有在内存中才会形成。
graph LR A(程序) --> B(字节流) B--> C>文件] A1(程序) --> B1(字符流) B1 --> C1(缓存) C1--> D1>文件]
字节流InputStream
- 通过 InputStream可以从文件中把内容读取进来
- InputStream本身也是一个抽象类,必须依靠其子类,如果现在是从文件中读取,子类是 FileInputStream
- 获取文件大小:直接使用 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
- OutputStream是一个抽象类,如果要想使用此类的话,则首先必须子类实例化对象,那么如果现在要操作的是一个文件,则可以使用:FileOutputStream类,通过向上转型之后,可以为 OutputStream实例化
- Closeable:表示可以关闭的操作,因为程序运行到最后肯定要关闭
- 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
- Writer抽象类,如果是向文件中写入内容,所以应该使用 FileWriter的子类
- 字符流的操作比字节流操作的优点:可以直接输出字符串,不用进行转换
Reader
- 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。