JAVA IO流
IO流概述
IO流是用来处理设备之间的数据传输
Java对数据的操作是通过流的方式
Java用于操作流的对象都在IO包中
分类
按照数据流向
1.输入流 读入数据
2.输出流 写出数据
按照数据类型
字节流 可以读写任何类型的文件 比如音频 视频 文本文件
字节流的抽象基类:
InputStream ,OutputStream。
字符流 只能读写文本文件
字符流的抽象基类:
Reader , Writer。
一.字节流
InputStream ,OutputStream是字节流的抽象基类。他有两对具体的子类FileInputStream,FileOutputStream、BufferedInputStream,BufferedOutputStream实现了该基类。 其中BufferedInputStream,BufferedOutputStream是高效字节流。
1.使用FileOutputStream写数据
构造方法
FileOutputStream(String name) 创建一个向具有指定名称的文件中写入数据的输出文件流。
FileOutputStream(String name, boolean append) 第二个参数为true则追加写入
FileOutputStream(File file) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
写入方法
public void write(int b):写一个字节 超过一个字节 砍掉前面的字节
public void write(byte[] b):写一个字节数组
public void write(byte[] b,int off,int len):写一个字节数组的一部分
//追加写入,每次都在文件后边写入,不会冲掉文件原本的内容
public class IODemo {
public static void main(String[] args) throws IOException {
//参数2 true 表示追加写入
// FileOutputStream(String name, boolean append)创建一个向具有指定 name 的文件中写入数据的输出文件流。
FileOutputStream out = new FileOutputStream("c.txt",true);
out.write("年少不听李宗盛".getBytes());
out.write("\r\n".getBytes());//写入换行符n
out.write("听懂已是不惑年".getBytes());
out.write("\r\n".getBytes());//写入换行符
out.write("初听不识曲中意".getBytes());
out.write("\r\n".getBytes());//写入换行符
out.write("再听已是曲中人".getBytes());
out.write("\r\n".getBytes());//写入换行符
out.close();
}
}
2.使用FileInputStream读取数据
构造方法
FileInputStream(File file) 创建一个向具有指定名称的文件中读取数据的输入文件流。
FileInputStream(String name) 创建一个向指定 File 对象表示的文件中读取数据的输入文件流。
读取方法
int read():一次读取一个字节
int read(byte[] b):一次读取一个字节数组
//一次读取一字节
public class IODemo {
public static void main(String[] args) throws IOException {
//输入流所关联的文件如果找不到就会报错
File file = new File("a.txt");
FileInputStream in = new FileInputStream(file);
len = in.read();
System.out.println(len);
//如果读取不到返回的是 -1
in.close();
}
}
//一次读取一个字节数组容量 相当于容器
public class IODemo2 {
public static void main(String[] args) throws IOException {
FileInputStream in = new FileInputStream("a.txt");
//相当于一个容器
byte[] bytes = new byte[1024];
in.read(bytes);//一次读取一个字节数组
String s = new String(bytes);
System.out.println(s);
//释放资源
in.close();
}
}
//使用字节数组来复制文件
public class CopyFile2 {
public static void main(String[] args) throws IOException {
FileInputStream in = new FileInputStream("yinyue.mp3");
FileOutputStream out = new FileOutputStream("E:\\acopy.mp3");
int len=0; //用来记录读取到的字节
//创建一个字节数组,用来充当缓冲区
byte[] bytes = new byte[1024 * 8];
while ((len=in.read(bytes))!=-1){
System.out.println("正在复制");
out.write(bytes,0,len);
out.flush();//刷新
}
System.out.println("复制完成");
//释放资源
in.close();
out.close();
}
}
3.使用高效字节流
高效字节流BufferedOutputStream,BufferedInputStream在底层使用了缓冲区来实现。
1.BufferedOutputStream
构造方法
BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
写方法与FileOutputStream相同。
2.BufferedInputStream
构造方法
BufferedInputStream(InputStream in)创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
BufferedInputStream(InputStream in, int size)创建具有指定缓冲区大小的BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
读方法与FileInputStream相同
public class IODemo {
public static void main(String[] args) throws IOException {
BufferedInputStream in = new BufferedInputStream(new FileInputStream("yinyue.mp3"));
//BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("yinyue2.mp3"));
int len=0;
byte[] bytes = new byte[1024 * 8];
while ((len=in.read(bytes))!=-1){
System.out.println("正在复制"+len);
out.write(bytes,0,len);
out.flush();
}
System.out.println("复制完成");
in.close();
out.close();
}
}
二.字符流
1.字符流与编码
字符流 = 字节流 + 编码表
编码:按照默认的码表进行编码,把看的懂变成看不懂的
解码:按照默认的码表进行解码,把看不懂的变成能看懂的
如果编码与解码参照的编码表不同,则会出现乱码。
字符流只能够读写文本文件,即可以使用记事本打开的文件。
把一个字符串转换成一个字节数组
public byte[] getBytes();使用平台的默认字符集将此 String编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
public byte[] getBytes(String charsetName) 使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
把字节数组转换成字符串
public String(byte[] bytes): 通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。
public String(byte[] bytes, String charsetName) 通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String。
2.基本字符流
1.OutputStreamWriter
构造方法
OutputStreamWriter(OutputStream out) 创建使用默认字符编码的OutputStreamWriter
OutputStreamWriter(OutputStream out,String charsetName) 创建使用指定字符编码的OutputStreamWriter。
写入方法
public void write(char c) 写一个字符
public void write(char[] cbuf) 写一个字符数组
public void write(char[] cbuf,int off,int len) 写一个字符数组的 一部分
public void write(String str) 写一个字符串
public void write(String str,int off,int len) 写一个字符串的一部分
注意:字符数组写入完要使用flush()方法刷新
public class IODemo {
public static void main(String[] args) throws IOException {
OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream("a.txt", true), "GBK");
//写入一个字符
out.write("你");
char[] chars = {'好', '好', '学', '习'};
out.write("\r\n");
out.flush();
out.write(chars);//一次写出一个字符数组
out.write("\r\n");
out.write(chars, 2, 2);//从2索引处 写两个字符
out.write("\r\n");
out.flush();
//写出一个字符串
out.write("去年今日此园中,人与桃花相映红.人面不知何处去,桃花依旧笑春风");
out.write("\r\n");
//写出字符串的一部分
out.write("桃花依旧笑春风", 4, 3);
out.flush();//字符流记得刷出一下
//释放资源
out.close();//关闭并刷新
}
}
2.InputStreamReader
构造方法
InputStreamReader(InputStream is):用默认的编码(GBK)读取数据
InputStreamReader(InputStream is,String charsetName):用指定的编码读取数据
读取方法
public int read() 一次读取一个字符
public int read(char[] cbuf) 一次读取一个字符数组 如果没有读到 返回-1
public class IODemo {
public static void main(String[] args) throws IOException {
//InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader。
//输入流 所关联的文件如果找不到就会报错
InputStreamReader in = new InputStreamReader(new FileInputStream("b.txt"));
//读取字符数据 一次读取一个字符,如果读取不到返回-1
int len = in.read();
System.out.println(len);
len = in.read();
System.out.println(len);
len = in.read();
System.out.println(len);
len = in.read();
System.out.println(len);
len = in.read();
System.out.println(len);
System.out.println("-----------------------------------");
}
}
3.便捷流
便捷流FileRader,FileWriter与InputStreamReader,OutputStreamWriter用法完全一样,只是更好记。
//标准异常处理的格式
public class IODemo {
public static void main(String[] args){
//如果你绝对字符转换流的名字太长,你可以用他的子类
// InputStreamReader ------FileRader
// OutputStreamWriter -----FileWriter
FileReader reader=null;
FileWriter writer=null;
try {
reader = new FileReader("MyDemo.java");
writer = new FileWriter("MyDemo1.java");
char[] chars = new char[1000];
int len=0;
while ((len=reader.read(chars))!=-1){
writer.write(chars,0,len);
writer.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(reader!=null){
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if(writer!=null){
writer.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4.高效字符流
BufferedWriter写出数据 高效的字符输出流
BufferedReader读取数据 高效的字符输入流
构造方法
public BufferedWriter(Writer w)
public BufferedReader(Reader e)
** 高效字符流可以使用字符流的读写方法**
特殊方法
BufferedWriter: public void newLine():根据系统来决定换行符 具有系统兼容性的换行符
BufferedReader: public String readLine():一次读取一行数据 是以换行符为标记的 读到换行符就换行 没读到数据返回null
//使用高效字节流一次复制一行
public class IODemo{
public static void main(String[] args) throws IOException {
//高效的字符流里面有特的方法
BufferedReader reader = new BufferedReader(new FileReader("MyDemo.java"));
BufferedWriter writer = new BufferedWriter(new FileWriter("MyDemo4.java"));
String line=null;
//reader.readLine() 高效字符输入流特有的方法,一次读取一行
//writer.newLine(); 高效字符输出流里面特有的方法
while ((line=reader.readLine())!=null){
writer.write(line);
writer.newLine();//写入一个换行符 具有平台兼容性
writer.flush();//记得刷新
}
//释放资源
reader.close();
writer.close();
}
}
三.一些其他流
1.数据输入输出流(字节流)
数据输入流: DataInputStream
数据输出流: DataOutputStream
public class IODemo {
public static void main(String[] args) throws IOException {
//字节流:数据输入输出流 他的特点是能够读写基本数据类型
//数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。
writerData();
readData();
}
private static void readData() throws IOException {
DataInputStream in = new DataInputStream(new FileInputStream("a.txt"));
int i = in.readInt();
System.out.println(i);
boolean b = in.readBoolean();
System.out.println(b);
double v = in.readDouble();
System.out.println(v);
char c = in.readChar();
System.out.println(c);
String s = in.readUTF();
System.out.println(s);
in.close();
}
private static void writerData() throws IOException {
DataOutputStream out = new DataOutputStream(new FileOutputStream("a.txt"));
//可以写基本数据类型
out.writeInt(100);
out.writeBoolean(true);
out.writeDouble(3.14);
out.writeChar('你');
out.writeUTF("爱生活,爱Java");
out.close();
}
}
2.内存操作流
内存操作流不关联文件,数据在内存中进行读写
此流关闭无效,所以无需关闭
此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
缓冲区会随着数据的不断写入而自动增长。
操作字节数组
ByteArrayOutputStream 此类实现了一个输出流,其中的数据被写入一个 byte 数组。
ByteArrayInputStream
可使用 toByteArray () 和 toString () 获取数据。
public class IODemo2 {
public static void main(String[] args) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write("好好学习,天天向上".getBytes());
out.write("爱生活,爱java".getBytes());
out.write("所有使你痛苦的,都是促使你成长".getBytes());
//将缓冲区中的数据取出来
byte[] bytes = out.toByteArray();
String s = new String(bytes);
System.out.println(s);
//String string = out.toString();
//System.out.println(string);
System.out.println("---------------------------------");
//从一个字节数组里面读取数据
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
byte[] bytes1 = new byte[1024];
stream.read(bytes1);
String s = new String(bytes1);
System.out.println(s);
//此流无序关闭
//out.close();
//stream.close();
}
}
操作字符数组
CharArrayWrite
CharArrayReader
可使用 toCharArray () 和 toString () 获取数据。
public class IODemo {
public static void main(String[] args) throws Exception{
//操作字符数组
// CharArrayWrite
//CharArrayReader
CharArrayWriter writer = new CharArrayWriter();
writer.write("abc");
writer.write("abc1");
writer.write("abc2");
writer.write("abc3");
writer.write("abc5");
char[] chars = writer.toCharArray();
String s = String.valueOf(chars);
System.out.println(s);
String string = writer.toString();
System.out.println(string);
}
}
操作字符串
StringWriter
StringReader
public class IODemo {
public static void main(String[] args) {
//操作字符串
// StringWriter
//StringReader
StringWriter writer = new StringWriter();
writer.write("abc");
writer.write("cc");
writer.write("aaaaa");
String string = writer.toString();
System.out.println(string);
}
}
3.打印流
打印流只能操作目的地,不能操作数据源(不能进行读取数据)
可以操作任意数据类型的数据 调用print() 方法可以写任意数据类型
如果我们启用自动刷新,那么在调用println、printf 或 format 方法中的一个方法的时候,会完成自动刷新
构造方法
PrintStream(String fileName)创建具有指定文件名称且不带自动行刷新的新打印流(字节流)
PrintStream(File file)创建具有指定文件且不带自动行刷新的新打印流。(字节流)
public PrintWriter(OutputStream out, boolean autoFlush) 启动自动刷新 (字符流)
public PrintWriter(Writer out, boolean autoFlush) 启动自动刷新(字符流)
//字节流
public class IODemo {
public static void main(String[] args) throws IOException {
//PrintStream(File file)
//创建具有指定文件且不带自动行刷新的新打印流。
PrintStream printStream = new PrintStream("b.txt");
printStream.println("abc");
printStream.print(3.14);
printStream.print(true);
printStream.println(3.14);
printStream.write("bbb".getBytes());
printStream.write("bbbb".getBytes());
printStream.close();
System.out.println("-----------------------------------");
//out 标准的输出流 关联的设备是屏幕
PrintStream out = System.out;
out.println("abc");
//System.out.println();
}
}
//字符流
public class IODemo2 {
public static void main(String[] args) throws IOException {
//字符打印流
PrintWriter writer = new PrintWriter(new File("c.txt"));
writer.write("abc");
writer.write("aaa");
writer.flush();
writer.println("asfasdfasdf");
writer.flush();
writer.println("asfadfadfsa");
writer.flush();
writer.close();
}
}
4.序列化流
序列化流: ObjectOutputStream
反序列化流: ObjectInputStream
序列化:就是把对象通过流的方式存储到文件中.注意:此对象 要重写Serializable 接口才能被序列化。使用transient关键字声明不需要序列化的成员变量(该成员变量不会被序列化)。
反序列化:就是把文件中存储的对象以流的方式还原成对象
写方法:writeObject()
读方法:readObject()
public class Student implements Serializable {
//把这个序列化id 也生成出来
private static final long serialVersionUID = 6253085787127234816L;
private String name;
transient public int age;
public int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = 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;
}
}
//序列化与反序列化Student对象
public class IODemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
writeObj();
readObj();
}
private static void readObj() throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("obj.txt"));
Object object = in.readObject();
//object=in.readObject();
//object=in.readObject();
//object=in.readObject();
Student stu = (Student) object;
System.out.println(stu.getName());
System.out.println(stu.getAge());
}
private static void writeObj() throws IOException {
Student student = new Student("张三", 23);
Student student2 = new Student("张三2", 23);
Student student3 = new Student("张三3", 23);
Student student4 = new Student("张三4", 23);
ObjectOutputStream obj = new ObjectOutputStream(new FileOutputStream("obj.txt"));
//把一个对象序列化到硬盘上
obj.writeObject(student); //序列化对象时 要求此类实现 Serializable 序列化接口
obj.writeObject(student2);
obj.writeObject(student3);
obj.writeObject(student4);
//NotSerializableException
}
}
//序列化与反序列化 使用List集合存储Studnet对象
public class IODemo7 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
writeObj();
readObj();
}
private static void readObj() throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("obj.txt"));
Object object = in.readObject();
ArrayList<Student> list = (ArrayList<Student>) object;
Student student = list.get(list.size() - 1);
System.out.println(student.getName());
System.out.println(student.getAge());
}
private static void writeObj() throws IOException {
Student student = new Student("张三", 23);
Student student2 = new Student("张三2", 23);
Student student3 = new Student("张三3", 23);
Student student4 = new Student("张三4", 23);
ArrayList<Student> list = new ArrayList<>();
list.add(student);
list.add(student2);
list.add(student3);
list.add(student4);
ObjectOutputStream obj = new ObjectOutputStream(new FileOutputStream("obj.txt"));
//把一个对象序列化到硬盘上
obj.writeObject(list); //序列化对象时 要求此类实现 Serializable 序列化接口
//NotSerializableException
}
}
5.随机访问流
RandomAccessFile概述 最大特点 能读能写。
RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能,支持对随机访问文件的读取和写入。
RandomAccessFile的父类是Object , 这个流对象可以用来读取数据也可以用来写数据.可以操作任意数据类型的数据. 我们可以通过getFilePointer方法获取文件指针,并且可以通过seek方法设置文件指针
//使用随机访问流实现断点续传
public class IODemo2 {
public static void main(String[] args) throws IOException {
RandomAccessFile r = new RandomAccessFile("yinyue.mp3", "rw");
RandomAccessFile w = new RandomAccessFile("yinyue2.mp3", "rw");
File file = new File("yinyue2.mp3");
if (file.exists()) {
long length = file.length();
//定位字节位置
r.seek(length);
w.seek(length);
} else {
r.seek(0);
w.seek(0);
}
copyFile(r,w);
}
private static void copyFile(RandomAccessFile r, RandomAccessFile w) throws IOException {
int len = 0;
byte[] bytes = new byte[100];
while ((len = r.read(bytes)) != -1) {
long pointer = r.getFilePointer();//获取文件指针位置
System.out.println(pointer);
w.write(bytes, 0, len);
}
r.close();
w.close();
}
}
6.Properties
Properties 类表示了一个持久的属性集。他可以保存在流中或从流中加载。Properties属于双列集合,父类是Hashtable,但是键与值都是Sting类型。不能知道泛型
创建对象 :Properties prop = new Properties() ;
添加元素 :public Object setProperty(String key,String value):
第一次添加元素的时候返回的是null
下一次添加元素的时候返回的是上一次键对应的值
根据键找值: prop.getProperty(name)
关联文件
public void load(Reader reader): 读取键值对数据把数据存储到Properties中
public void store(Writer writer, String comments)把Properties集合中的键值对数据写入到文件中, comments注释//键与值之间使用“=”链接
//存入文件
public class IODemo {
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
properties.setProperty("zhangsan","123456");
properties.setProperty("zhangsan2", "123456");
properties.setProperty("zhangsan3", "123456");
properties.setProperty("zhangsan4", "123456");
properties.setProperty("赵六", "123456");
//把集合中的数据写入到配置文件当中去
properties.store(new FileOutputStream("student.properties"),null);
}
}
//读取文件
public class IODemo3 {
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
//Properties 这个集合 读取配置文件中的数据放到集合中去,配置文件中的键值要用=拼接
//key=vaule
properties.load(new FileReader("user.properties"));
String v = properties.getProperty("wangwu");
System.out.println(v);
}
}