一、流的概念
流是一组有序数据序列,它将数据从一个地方带到另外一个地方。Java中所有的数据都是使用流来读写的。根据流向的不同将流分为输入(Input)流和输出(Output)流两种。Java流功能都封装在java.io包中。
流的分类:
1. 按照流的方向主要分为输入流和输出流。
2. 按照数据单位的不同分为字节流字符流。
3. 按照功能划分为节点流和处理流。
二、输入流
-
所有输入流类都是 InputStream 抽象类(字节输入流)和 Reader 抽象类(字符输入流)的子类。其中 InputStream 类是字节输入流的抽象类,是所有字节输入流的父类
图片来自网络。
InputStream 类中所有方法遇到错误时都会引发 IOException 异常,InputStream类的常用方法:- int read(); //每次读取8个字节的数据,并转换成0~255的整数返回,如果遇到输入流结尾返回-1
- int read(byte[]b); //读取若干个字节保存到指定的数组b中,然会读到的字节数,如果遇到流结尾返回-1
- int read(byte[], int offset, int len);
- void close();
- int available(); //返回可以从数据源读取的数据流的位数
- skip(long n);
- boolean markSupported(); //判断输入流是否可以重复读取,如果可以返回true,否则返回false
- void mark(int readLimit); //如果可以重复读取,从刘的当前位置做标记,readLimit指定可以设置标记的子结数
- void reset(); //如果可以重复读取,复位到刚才被标记的位置,之后就可以重新去读标记过的数据。
-
InputStream使用来处理单字节的,但是Java中的字符是Unicode编码,即双字节。当处理字符文本时就很不方便。因此Java提供了Reader类。该类是字符输入流的抽象类,即所有字输入流的实现都是它的子类。
图片来自网络
三、输出流
- Java 中所有输出流类都是 OutputStream 抽象类(字节输出流)和 Writer 抽象类(字符输出流)的子类。其中 OutputStream 类是字节输出流的抽象类,是所有字节输出流的父类,
图片来自网络
OutputStream类是所有字节输出流的超类,用于一二进制的形式将数据写入目标设备,该类是抽象类,不能被实例化。
OutputStream类方法:
-
int write(b);
-
int write(byte[]b);
-
int write(byte[]b, int offset, int len);
-
close();
-
flush();
-
字符输出流的父类Writer
图片来自网络
四、字节数组输入输出流
1. 字节数组输入流:
构造方法:
1. ByteArraryInputStream(byte[] buf);
2. ByteArrayInputStream(byte[] buf, int offset, int num);
2. 字节流数组输出流:
构造方法:
1. ByteArrayOutputStream();
2. ByreArrayOutputStream(int size);
实例:
public static void myJavaIOTest( ) {
byte[] inputArray = new byte[]{1, -1, 2, 127, 0}; //java byte的范围[-128, 127]
//ByteArrayInputStream bais = new ByteArrayInputStream(inputArray, 3, 10);
ByteArrayInputStream bais = new ByteArrayInputStream(inputArray);
Integer num = bais.read(); //read()将byte转换成int[0, 255]返回
while(num != -1) {
System.out.printf("%d\t", num);
num = bais.read();
}
System.out.println();
byte[] outputArray = new byte[10];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(inputArray, 0, 5);
System.out.printf("outputArray size:%d\n", baos.size());
byte[] newOutputArray = baos.toByteArray();
System.out.println(Arrays.toString(newOutputArray));
}
输出结果:
1 255 2 127 0 //注释1
outputArray size:5
[1, -1, 2, 127, 0]
注释1:
Java中byte的范围是[-128, 127];
-1变成了255,负数的二进制形式以补码的形式保存。
-1的二进制存放形式:
1的原码是00000001,然后反码为11111110, 然后进行补码操作(末尾位加1),变成11111111。
五、文件输入输出流
1. 文件输入流
构造函数:
1. FileInputSttream(File file);
2. FileInputStream(String name);
2. 文件输出流
构造函数:
1. FileOutputStream(File file);
2. FileOutputStream(File file, boolean append);
3. FileOutputStream(String name);
4. FileOutputStream(String name, boolean append);
注意:append为true表示追加,false表示覆盖从0开始写。
实例:
public static void javaFileIOTest() {
Integer val = -1;
byte[] readBuffer = new byte[1024];
try {
FileInputStream fis = new FileInputStream("/home/gchuan/eclipse-workspace/lesson3/a.txt");
try {
val = fis.available(); //get file size
while((val = fis.read(readBuffer)) != -1) {
System.out.printf("Val = %d\n", val);
String buffer = new String(readBuffer, 0, val);
System.out.println(buffer);
}
} catch (Exception e) {
e.printStackTrace();
}
finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("======================================");
File fileOutput = new File("/home/gchuan/eclipse-workspace/lesson3/b.txt");
try {
@SuppressWarnings("resource")
FileOutputStream fos = new FileOutputStream(fileOutput);
fos.write(readBuffer);
fos.write(readBuffer, 0, val);
fos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
六、字符输入输出流
1. 文件输入流
构造函数:
1. FileReader(File file);
2. FileReader(String name);
2. 文件输出流
构造函数:
1. FileWrite(File file);
2. FileWrite(File file, boolean append);
3. FileWrite(String name);
4. FileWrite(String name, boolean append);
注意:append为true表示追加,false表示覆盖从0开始写。
代码参考字节输入输出实例
七、系统流
Java系统流封装在java.lang.System类中,每个Java程序运行时自带3个系统流,即:System.in、System.out、System.err。而且变量in、out、err作用域是public和static的。因此程序不需要引用System对象就可以使用。
System.in //标准输入流,默认设备就是键盘
System.out //标准输出流,默认设备是控制台
System.err //标准错误流,默认设备是控制台
实例:
public static void javaSystemIOTest() {
byte[] readBuffer = new byte[1024];
System.out.println("请输入文字:");
try {
System.in.read(readBuffer);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("输入内容:" + (String)(new String(readBuffer)));
}
输出结果:
请输入文字:
Java 系统IO 输入输出
输入内容:Java 系统IO 输入输出
八、Java 动态读取
动态读取是指从文件的任意位置访问文件,而不是必须冲开始读取到文件末尾。
动态读取需要用到JavaRandomAccessFile类,该类有一个文件指针用于标识当前流的读写位置,且可以前后移动。
构造方法:
RandomAccessFile(File file, String mode);
RandomAccessFile(String name, String mode);
参数:
mode:r - 只读 | rw - 读写
RandomAccessFile类方法:
1. boolean readBoolean();
2. byte readByte();
3. char readChar();
4. int readInt();
5. long readLong();
6. String readLong();
7. void seek(long offset);
8. void writeBoolean(boolean value);
9. void writeByte(int value);
10. void writeChar(int value);
11. void writeInt(int value);
12. writeLong(long value);
13. void writeBytes(String str);
14. void skipBytes(int number);
实例:
public static void javaRandomAccessTest() {
int val = -1;
byte[] buffer = new byte[1024];
try {
RandomAccessFile raf = new RandomAccessFile("/home/gchuan/eclipse-workspace/lesson3/c.txt", "rw");
raf.writeBytes("java randmo access file test.\n");
/*
raf.close();
RandomAccessFile rafr = new RandomAccessFile("/home/gchuan/eclipse-workspace/lesson3/c.txt", "r");
System.out.printf("file size:%d\n", size);
while ((val = rafr.read(buffer, 0, 5)) != -1) {
System.out.println(new String(buffer, 0, val));
}
rafr.close();
*/
raf.seek(5);
val = raf.read(buffer, 0, 1024);
System.out.printf("read return value:%d\n", val);
System.out.println(new String(buffer, 0, val));
raf.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
输出结果:
read return value:25
randmo access file test.