字节流
IO流分为输入流、输出流。
java中读文件/写文件时又分为字节流、字符流。
1、字节流
(1)字节流的抽象父类:InputStream,OutputStream.
InputStream抽象了应用程序读取数据的方式;
OutputStream抽象了应用程序写出数据的方式。
(2)EOF = End 读到-1就是读到了结尾
(3)输入流基本方法
int b = in.read(); //读取一个字节无符号填充到int低八位,读到-1就是读到了结尾 此方法为读取一个字节
in.read(byte[] buf); //读到一个字节数组中
in.read(byte[] buf, int start, int size); //数据从开始到指定长度读到一个字节数组中
(4)输出流基本方法
out.write(int b); //写出一个byte到流,b的低八位
out.write(byte[] buf); //将buf字节数组都写入到流
out.write(byte[] buf); //将buf字节数组从开始到指定长度写入到流
(5)FileInputStream --> InputStream的子类,具体实现了在文件上读取数据
(6)FileOutputStream --> OutputStream的子类,具体实现了向文件中写出byte数据的方法
(7)DataInputStream/DataOutputStream(数据流)
对“流”功能的扩展,可以更加方便的读取int、long、String等类型数据。
(8)BufferedInputStream&BufferedOutputStream(缓冲流)
这两个流为IO提供了带缓冲区的操作,一般打开文件进行写入或读取操作时,都会加上缓冲,这种流模式提高了IO的性能。
从应用程序中把输入放进文件,相当于将一缸水倒入另一个缸中:
FileOutputStream --> write() 方法相当于将水一滴一滴“转移”过去,
DataOutputStream --> writeXxx() 方法会方便一些,相当于把水一瓢一瓢地“转移”过去,
BufferedOutputStream --> write() 方法更方便,相当于一瓢一瓢先放入桶中,再从桶中倒入缸中。
案例:FileInputStream读取文件内容
写一个IOUtils工具类,用于读取指定文件内容并按照16进制输出到控制台(两种方法):
public class IOUtils {
/**
* 读取指定文件内容,按照16进制输出到控制台
* 并且每输出10个byte换行
* @param fileName
* @throws IOException
*/
public static void printHex(String fileName) throws IOException {
// 把文件作为字节流进行读操作
FileInputStream fis = new FileInputStream(fileName);
int len;
int i = 1;
while ((len = fis.read()) != -1) {
if (len <= 0xf) { //len <= 0xf:说明只读到了一位
// 单位数前面补零
System.out.print("0");
}
System.out.print(Integer.toHexString(len) + " ");
if (i++ % 10 == 0) {
System.out.println();
}
}
fis.close();
}
public static void printHexByByteArray(String fileName) throws IOException {
FileInputStream fis = new FileInputStream(fileName);
byte[] buf = new byte[1024];
/**
* 从fis中批量读取字节,放入到buf这个字节数组中,
* 从第0个位置开始放,最多放buf.length个,
* 返回的是读到的字节的个数
*/
int bytes = fis.read(buf, 0, buf.length); //如果一次性读完了,说明字节数组足够大
int j = 1; //用于计数
for (int i = 0; i < bytes; i++) {
if (buf[i] <= 0xf) {
System.out.print("0"); //单位数补零
}
System.out.print(Integer.toHexString(buf[i] & 0xf) + " ");
if (j++ % 10 == 0) {
System.out.println();
}
}
}
}
测试类:
public class IOTest {
public static void main(String[] args) {
try {
IOUtils.printHex("F:\\Code\\JavaSE\\raf.txt");
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("========================");
try {
IOUtils.printHexByByteArray("F:\\Code\\JavaSE\\raf.txt");
} catch (IOException e) {
e.printStackTrace();
}
}
}
以上两种方式的输出结果相同,只是读出的方法稍微不同。
案例:FileOutputStream写出数据
public class FileOutputTest {
public static void main(String[] args) throws IOException {
// 如果该文件不存在,则直接创建;如果存在,则删除后创建
// FileOutputStream fos = new FileOutputStream("F:\\Code\\JavaSE\\raf.txt");
/*
如果该文件不存在,则直接创建;如果存在,则向该文件中追加数据
其中,第二个参数为是否追加数据,true表示追加,false表示不追加
*/
FileOutputStream fos = new FileOutputStream("F:\\Code\\JavaSE\\raf.txt", true);
fos.write('A');// 写出'A'的低八位
fos.write('B');// 写出'B'的低八位
int a = 10;// write只能写8位,则写一个int类型的数据需要写4次,每次8位
fos.write(a >>> 24);
fos.write(a >>> 16);
fos.write(a >>> 8);
fos.write(a);
byte[] bytes = "中国".getBytes("GBK");
fos.write(bytes);
fos.close();
IOUtils.printHex("F:\\Code\\JavaSE\\raf.txt");
}
}
案例:输入输出流结合 - 拷贝文件(开辟字节,批量读取)
IOUtils工具类中添加copyFile方法:
public static void copyFile(File srcFile, File dirFile) throws IOException {
if (!srcFile.exists()) {
throw new IllegalArgumentException(srcFile+"文件不存在~");
}
if (!srcFile.isFile()) {
throw new IllegalArgumentException(srcFile+"不是文件~");
}
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(dirFile);
byte[] buf = new byte[1024];
int len;
while ((len = fis.read(buf)) != -1) {
fos.write(buf, 0, len);
fos.flush();// 清空缓冲区数据
}
System.out.println("copy完成~");
fos.close();
fis.close();
}
测试类:
public class CopyFileTest {
public static void main(String[] args) {
try {
IOUtils.copyFile(new File("F:\\Code\\JavaSE\\raf.txt"), new File("F:\\Code\\JavaSE\\raf_copy.txt"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出结果:copy完成~
打开目标文件位置,可以看到已存在拷贝的文件。
案例:使用数据流将数据写入文件中并读出
public class DosDemo {
public static void main(String[] args) {
DataOutputStream dos = null;
DataInputStream dis = null;
try {
String file = "F:\\Code\\JavaSE\\dos.txt";
dos = new DataOutputStream(
new FileOutputStream(file));
dos.write(10);
dos.writeByte(20);
dos.writeInt(30);
dos.writeLong(-10L);
dos.writeDouble(-20.5);
dos.writeUTF("中国"); //以utf-8编码写出
dos.writeChars("雄狮"); //以utf-16be编码写出
dis = new DataInputStream(new FileInputStream(file));
int read = dis.read();
System.out.println(read);
byte b = dis.readByte();
System.out.println(b);
int i = dis.readInt();
System.out.println(i);
long l = dis.readLong();
System.out.println(l);
double v = dis.readDouble();
System.out.println(v);
String s = dis.readUTF();
System.out.println(s);
System.out.print(dis.readChar());
System.out.println(dis.readChar());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (dis != null) {
dis.close();
}
if (dos != null) {
dos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
输出结果:
10
20
30
-10
-20.5
中国
雄狮
案例:使用缓冲流拷贝文件(速度最快)
IOUtils工具类中写一个缓冲流拷贝文件方法:
// 进行文件的拷贝,利用带缓冲的字节流
public static void copyFileByBuffered(File srcFile, File dirFile) throws IOException {
if (!srcFile.exists()) {
System.out.println(srcFile + "文件不存在~");
}
if (!srcFile.isFile()) {
System.out.println(srcFile + "不是一个文件~");
}
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dirFile));
int len;
while ((len = bis.read()) != -1) {
bos.write(len);
bos.flush();// 刷新缓冲区,否则写入不到文件中(不带缓冲可以不刷新缓冲区)
}
// 关闭流
bos.close();
bis.close();
System.out.println("拷贝完成~");
}
}
测试类:
public class BufferedTest {
public static void main(String[] args) throws IOException {
IOUtils.copyFileByBuffered(
new File("F:\\Code\\JavaSE\\raf.txt"), new File("F:\\Code\\JavaSE\\buf.txt"));
}
}
输出结果:拷贝完成~
传输速度:
(FileOutputStream)单字节输出流 > (FileOutputStream)输出流批量读取 > (BufferedOutputStream)缓冲流读取.