java i/o 的一些操作
文件流:FileInputStream/FileOutputStream, FileReader/FileWriter
- 这四个类是专门操作文件流的,用法高度相似,区别在于前面两个是操作字节流,后面两个是操作字符流。它们都会直接操作文件流,直接与OS底层交互。因此他们也被称为节点流。
package com.lw.study.excelTest;
import com.lw.study.Application;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.io.*;
/**
* @author:
* @Date: 15:21 2019/2/28
*/
@SpringBootTest(classes = Application.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class FileTest {
// 字节流没有缓冲区,是直接输出的,而字符流是输出到缓冲区的。因此在输出时,字节流不调用colse()方法时,信息已经输出了,
// 而字符流只有在调用close()方法关闭缓冲区时,信息才输出。要想字符流在未关闭时输出信息,则需要手动调用flush()方法。
@Test
public void testGetFile() throws IOException {
//字节流
String filepath = "/tmp/dashu/test.txt";
OutputStream outputStream = new FileOutputStream("/tmp/dashu/test3.txt");
InputStream inputStream = new FileInputStream(filepath);
try {
byte[] b = new byte[inputStream.available()];
System.out.println(inputStream.available());
inputStream.read(b);
System.out.println(new String(b));
outputStream.write(b);
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
inputStream.close();
outputStream.close();
}
}
@Test
public void testWrite() {
//字符流
try {
//若文件不存在会新建一个文件,然后写入内容,文件存在覆盖源文件内容
FileWriter fw = new FileWriter("/tmp/dashu/test4.txt");
FileReader fd = new FileReader("/tmp/dashu/test2.txt");
char[] read = new char[32];
int hasRead = 0;
while ( (hasRead =fd.read(read)) > 0) {
// System.out.println(read);
String readLine = new String(read, 0, hasRead);
System.out.println(readLine);
//一定要关闭这个溜。不然会写不进去
//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。
//将数据刷到目的地中去。
//和flush区别:flush 刷新后,流可以继续使用,close刷新后,会将流关闭。
// 实际上,当我们写好了new FileWriter 的时候,我们进行下一步的操作,将数据写入文本,但是这时的数据并没有写入文本,而是存在了计算机中的流中。这也是JAVA能够在Windows 系统中调用文本流的作用。而如果在这里我们使用fw.flush时,是可以将存储在计算机流中的数据放入fw的,但是如果我们之后再想加入数据的时候,也就是说我们将写入的数据这句话放在fw.flush之后的话,之后输入的数据就不会放入到 test.txt中去。
// 再说一说fw.close, 我们可以去查询close的定义,很明确的写了 先刷新一次,然后关闭数据流。没错,事实上,close是包含了两步,flush 和close 这两步。所以我们注释掉了flush 因为在这里一个close语句就够用了。
// flush 刷新后,流可以继续使用,close刷新后,会将流关闭。
//
fw.write(readLine);
fw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 字符缓冲流 用来读取纯文本文件
* @throws IOException
*/
@Test
public void testBufferReader() throws IOException {
try {
BufferedReader bufferedReader = new BufferedReader(new FileReader("/tmp/dashu/test.txt"));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("/tmp/dashu/test5.txt"));
//保存每次读取的一行的内容
String line = "";
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
bufferedWriter.write(line);
//换行
bufferedWriter.newLine();
}
bufferedReader.close();
bufferedWriter.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
/**
*字节缓冲流,读取图片、视频等
* @throws IOException
*/
@Test
public void testBufferInputStream() throws IOException {
BufferedInputStream in = new BufferedInputStream(new FileInputStream("/tmp/dashu/终端背景.jpg"));
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("/tmp/dashu/终端背景2.jpg"));
byte[] bRead = new byte[in.available()];
in.read(bRead);
out.write(bRead);
in.close();
out.close();
}
}
总结几种流的应用场景:
- FileInputStream/FileOutputStream 需要逐个字节处理原始二进制流的时候使用,效率低下
- FileReader/FileWriter 需要组个字符处理的时候使用
- StringReader/StringWriter 需要处理字符串的时候,可以将字符串保存为字符数组
- PrintStream/PrintWriter 用来包装FileOutputStream 对象,方便直接将String字符串写入文件
- Scanner 用来包装System.in流,很方便地将输入的String字符串转换成需要的数据类型
- InputStreamReader/OutputStreamReader , 字节和字符的转换桥梁,在网络通信或者处理键盘输入的时候用
- BufferedReader/BufferedWriter , BufferedInputStream/BufferedOutputStream , 缓冲流用来包装字节流后者字符流,提升IO性能,BufferedReader还可以方便地读取一行,简化编程。
- StringBufferInputStream – 把一个 String 对象作为。InputStream。不建议使用,在转换字符的问题上有缺陷
注意:
available()来获取文件的总大小,这个方法在获取本地文件的时候没啥问题,但是如果是获取网络文件的大小,如果网络阻塞了,inputstream已经打开,但是数据却还没有传输过来,那么这个inputstream势必会被阻塞,从而导致inputstream.available返回0。而对inputstream.read(byte[] b)而言,如果b的长度等于0,该方法将返回0。可以考虑手工设定一个固定值;或者读取http报文头的content-length属性值,后一种方式:
URLConnection openConnection = new URL("http://www.apache.org").openConnection();
System.out.println(openConnection.getContentLength());
available()这个方法其实是通过文件描述符获取文件的总大小,而并不是事先将磁盘上的文件数据全部读入流中,再获取文件总大小。