一、IO流原理及流的分类
IO的原理
IO是Input/Output 的缩写,I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。
Input (流入) Output (流出)
按照方向分类 (站在程序这一端)
输入流(读) :外界数据(磁盘、数据库、网络、键盘(Scanner)) ---> 程序
输出流(写) :程序--->外界(磁盘、数据库、网络、显示器)
按照处理数据单位分
字节流 (图片、视频、音频、小文本) :每次操作一个字节
字符流 (大文本) :每次操作一个字符
按照角色分
节点流(原始流)就是基础流
处理流:在节点流的基础上,通过对数据的处理为程序提供更为强大的读写功能。
二、流的体系结构
字节输入流
InputStream
BufferedInputStream
ObjectInputStream
字节输出流
OutputStream
BufferedOutputStream
ObjectOutputStream
字符输入流
Reader
BufferedReader
字符输出流
Writer
BufferedWriter
四、四个基础流
1、 InputStream
图片只能使用字节流
a. InputStream 是一个抽象类
实现类:FileInputStream 主要是读取磁盘上的文件
b. FileInputStream的构造器
FileInputStream(File file);//通过File类对象去构建输入流对象
FileInputStream(String path);//通过路径去构建处输入流对象
c. 操作步骤
a. 创建流对象
b. 进行读写操作
c. 关闭资源
@Test
public void test1() {
InputStream input = null;
File file =new File("src//python.txt");
try {
input=new FileInputStream(file);
//读写操作
int k=-1;
while((k=input.read())!=-1) {
System.out.print((char)k);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
input.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
d. 读取的方法
int read();每执行一次读取一个字节,并且指针后移
length=in.read(b);//将数据存储在byte[]中,返回的int值是读取的字节数int
int len=in.read(b, 2, 5);//将数据存储在数据中,从指定下标位置(2)开始存,存指定字节数(5)个
e. 全部读取方式
① read() 这个循环之前不能出现read方法
for (int j2 = 0; j2 < file.length(); j2++) {
System.out.print((char)in.read());
}
★ ② b. read() 在读取到没有时返回-1
//in.read();返回的是读取一次的字节
int k=0;
while((k=in.read())!=-1){
System.out.print((char)k);
}
③ in.read(b);
byte[] b=new byte[(int)file.length()];
int length=in.read(b);
for (int i = 0; i < b.length; i++) {
System.out.print((char)b[i]);
}
★ ④ in.read(b);
//input.read(v)返回的是读取了多少个字节(字节数)
byte[] b=new byte[10];
int len;
while((len=in.read(b))!=-1){
for (int i = 0; i < len; i++) {
System.out.print((char)b[i]);
}
}
结论
- 对于文本文件(.txt ,.java,.c,.cpp),使用字符流处理
- 对于非文本文件(.JPG,.mp3, .mp4,.avi,.doc,.ppt, .....) 使用字节流处理
- 使用字节流处理文本文件是可能出现乱码的
f. 练习
从磁盘上找一个文件,封装成File对象,作为参数传递给io流,分别采用四种方式读取文件内容到控制台
@Test
public void test2() {
InputStream input = null;
File file =new File("src//python.txt");
try {
input=new FileInputStream(file);
//读写操作
byte[] b=new byte[10];
int k;
while((k=input.read(b))!=-1) {
for (int i = 0; i < k; i++) {
System.out.print((char)b[i]);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
input.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2、 OutputStream
a.OutputStream 是一个抽象类
b.FileOutputStream 一个实现类
构造器
FileOutputStream(File file);//写入的内容会覆盖原本的内容
FileOutputStream(File file,boolean append);//布尔值设置为true,代表追加内容
FileOutputStream(String path);//写入的内容会覆盖原本的内容
FileOutputStream(String path,boolean append);//布尔值设置为true,代表追加内容
c. 特点:
a. 输出流指向的文件夹必须存在,但是指向的文件是可以不存在的,在新建流时会创建该文件
d. 常用方法
write(int b);每次写入一个字节 (和InputStream中read())
write(b);//将byte[]中的数据全部写入 (和InputStream中的read(b))
write(b, 2, 3);//奖byte[]中的数据从指定索引值(2)开始写,写入指定个数(3)
(和InputStream中的read(b,index,length))
(一般情况下我们都会将此方法和read(b)一起用)
e. 练习
1. 将main方法的方法签名写入到d:hello.java
@Test
public void test1() {
OutputStream out=null;
try {
String str="public static void main(String[] agrs)";
byte [] b=str.getBytes();
out=new FileOutputStream(new File("src//java.java"));
for (int i = 0; i < b.length; i++) {
out.write(b[i]);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2. 将hello.java复制到f盘根目录 从一个文件读到程序,在将内容写入到一个文件
write(int b)和read()
write(b, 2, 3); 和 read(b);
@Test
public void test2() {
InputStream input = null;
OutputStream out=null;
try {
input=new FileInputStream(new File("src//Demo//29.jpg"));
out=new FileOutputStream(new File("src//32.jpg"));
//读操作
byte[] b=new byte[1024];
int k;
while((k=input.read(b))!=-1) {
for (int i = 0; i < k; i++) {
out.write(b[i]);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
input.close();
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3 、Reader
a. Reader 也是一个抽象类
b. 实现类 FileReader (操作方式和InputStream类似,只是操作的单位不一样)
构造器
FileReader(File file)
FileReader(String path)
c. 常用方法
read();每次读取一个字符
read(char[] c);将读取的内容存放在char[]中,返回的是读取的字符数
len=r.read(c, 3, 5);将读取的数据内容存放在char[]中,从指定索引值(3)开始存,存指定个数(5)的字符
d. 读取全部内容的方式
a. read();
int i;
while((i=r.read())!=-1){
System.out.print((char)i);
}
b. read(c);
char[] c=new char[5];
int len=0;
while((len=r.read(c))!=-1){
for (int i = 0; i < len; i++) {
System.out.print(c[i]);
}
}
4、 Writer
① Writer是一个抽象类
② 实现类是 FileWriter
-
输出操作对应的file 可以不存在,
-
如果不存在,输出的过程中会自动创建此文件。
-
如果存在fileWriter(file,false)/fileWriter(file)自动覆盖,fileWriter(file,ture 追加
-
构造器
FileWriter(File file) //覆盖内容
FileWriter(File file, boolean append) //追加内容
FileWriter(String path)
FileWriter(String path, boolean append)
③ 常用方法
write(int b);每次写一个字符
write(char[] c);将char[]中的数据全部写入
write(char[] c,int off,int length);将数组中的数据 从off开始写,写length个
write(String str);将字符串内容全部写入
write(String str,int off,int length);将字符串中的 字符从off开始写,写length个
④. 练习
使用字符流完成文件的复制,两种方式去实现
@Test
public void test1() {
Reader r=null;
Writer w=null;
try {
w=new FileWriter(new File("src//Demo//copy.txt"));
r=new FileReader(new File("src//python.txt"));
int len;
char[] c=new char[5];
while((len=r.read(c))!=-1) {
w.write(c,0,len);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
r.close();
w.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
@Test
public void test2() {
Reader r=null;
Writer w=null;
try {
w=new FileWriter(new File("src//Demo//copy.txt"));
r=new FileReader(new File("src//python.txt"));
int len;
while((len=r.read())!=-1) {
w.write((char)len);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
r.close();
w.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
5、缓冲流
a. 字节流 输入流 缓冲流
字节输入缓冲流在使用上和InputStream没有差别,只不过自带一个缓冲区,提高效率
BufferedInputStream in=
new BufferedInputStream(
new FileInputStream(new File("d:\hello.java")));
b. 字节流 输出流 缓冲流
字节输出缓冲流在使用上和OutputStream没有差别,只不过自带一个缓冲区,提高效率
BufferedOutputStream out=
new BufferedOutputStream(new FileOutputStream("f:\aa.txt"));
c. 字符流 输入流 缓冲流
字符输入缓冲流在使用上功能要比Reader多一个readLine();其他方法使用是一致的
//in.readLine();每次读取一行,读到末尾返回null
BufferedReader in=
new BufferedReader(
new FileReader("f:\hello.java"));
String str=null;
while((str=in.readLine())!=null){
System.out.println(str);
}
d. 字符流 输出流 缓冲流
字符输出缓冲流在使用上功能比Writer多了一个newLine();其他的使用是一致的
//newLine();新的一行 一个换行
BufferedWriter out=
new BufferedWriter(
new FileWriter("f:\world.java"));
out.write("今天是周五");
out.newLine();//新的一行 一个换行
out.write("明天是周六");
out.close();
6、对象流
Java中的对象<———>文件
a.ObjectInputStream
- 创建对象
ObjectInputStream in=
new ObjectInputStream(
new FileInputStream("f:\person.txt"));
- readInt();readByte();readObject()...
注意:写入的方法和读取的方法类型要一致
b.ObjectOutputStream
- 创建对象
ObjectOutputStream out=
new ObjectOutputStream(
new FileOutputStream("f:\person.txt"));
2. 常用方法
writeInt();writeByte();writeObject();...
3. 对象流写入对象时,对 对象有些要求,这个对象必须能序列化
序列化的步骤 实现Serializable接口,(该接口中没有任何抽象方法)
并添加:private static final long serialVersionUID = 1L;
作用:主要是为了版本的兼容性
3. 练习
自己创建一个类,然后创建该类的对象,并将该对象写入到一个文件中,在读取出来
* 此文件主要演示:把对象存储到文本文件中,使用对象输入流和对象输出流
public void test1() {
ObjectOutputStream obj=null;
ObjectInputStream in=null;
try {
obj=
new ObjectOutputStream(
new FileOutputStream(
new File("src//Demo//animal.text")));
in=
new ObjectInputStream(
new FileInputStream(
new File("src//Demo//animal.text")));
obj.writeObject(new Animal("灯泡",1));
Object o=in.readObject();
System.out.println(o);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
obj.close();
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class Animal implements Serializable{
private static final long serialVersionUID = 7809121654099691241L;
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Animal [name=" + name + ", age=" + age + "]";
}
public Animal(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
7、打印流
a.打印流 主要处理的是 输出流
b. 字节打印输出流 PrintStream
构造器
PrintStream(OutputStream out);
PrintStream(OutputStream out, boolean autoFlush);//带自动刷新功能
c.字符打印输出流 PrintWriter
构造器
PrintWriter(Writer out);
PrintWriter(Writer out, boolean autoFlush);
d. 特点
a. 提供了一系列重载的print和println方法,用于多种数据类型的输出
b. PrintStream和PrintWriter的输出不会抛出异常
c. PrintStream和PrintWriter有自动flush功能
只针对 println, printf,或 format
d. System.out返回的是PrintStream的实例
构造器
printStream(OutputStream out);
8、标准输入输出流
标准的输入输出流
1、printStream=System.out ——————-(显示器:控制台)
更改System.out的指向位置
setOut(OutputStream out)
2、InputStream=System.in-----------------------(键盘)
更改System.in的指向位置
System.SetIn(InputStream in);
PrintStream =System.err();//打印字体是红色的
9、转换流
- 字节流 ---> 字符流
a. 输入流
InputStream--->Reader
Reader r=new InputStreamReader(InputStream,String charset);//String charset。 指定字符集
b. 输出流
OutputStream--->Writer
Writer w=new OutputStreamWriter(OutputStream,String charset);
- 练习
模仿Scanner制作一个readLine() 读一行
(System.in、InputStreamReader、BufferedReader)
package homework;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
/*1.去模仿Scanner去写俩个方法
nextLine();//获取一行 BufferedReader
nextInt();
*/
public class homework {
public static void main(String[] args) {
// nextLine();
nextInt();
}
public static void nextLine() {
System.out.println("请输入文字:");
InputStream in=System.in;//接收键盘输入
Reader r=new InputStreamReader(in);//使用字节流转换成字符流
BufferedReader br=new BufferedReader(r);//Reader转换成缓冲字符流
String str=null;
try {
str = br.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(str);
}
public static void nextInt() {
System.out.println("请输入数字:");
InputStream in=System.in;//接收键盘输入
Reader r=new InputStreamReader(in);//使用字节流转换成字符流
BufferedReader br=new BufferedReader(r);//Reader转换成缓冲字符流
String a=null;
try {
while((a = br.readLine())!=null) {
System.out.print(a);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
10、Properties
此类用于演示Map集合实现类 Properties
- Properties HashTable的子类 所以具备HashTable所有的特点
一般读取配置文件
- Properties能够读取配置文件(文件名.properties/.xml)
文件名.properties的编码格式为 ISO-8859-1
Properties pro=new Properties();
- pro.load(new FileInputStream("srcusers.properties"));指向配置文件
getProperty(String key);根据key值获取value值
getProperty(String key,String defaultValue);根据key值获取value值,如果取不到返回默认值
pro.list(System.out);打印文件所有内容
- 写入常用方法
Properties pro=new Properties();
setProperty(String key, String value);设置文件内容
pro.store(OutputStream out, String commons);设置写到的位置OutputStreamout 写到某一个文件