您的位置:首页 > 编程语言 > Java开发

Java-IO流总结

2017-06-12 08:56 106 查看

IO流:

IO流分为两大类:字节流和字符流

IO的作用就是为了读写操作的。

每种流都分为输入流(Input)、输出流(Output);站在java程序的角度来说,java程序进行读取操作时,就是输入流;如果java程序向其他地方(硬盘,其他的设备)写入操作时,就是输出流。

IO流只能操作文件,不能操作文件夹,否则会报错。

字节流:

字节输入流:InputStream

字节输出流:OutputStream

OutputStream:

可以向文件中写入字节,进行写入常用的是OutputStream的子类:FileOutputStream,常用的写入方法是write(byte[]),传入byte数组。

下面将是演示利用FileOutputStream来进行写入文件:

package com.xiaoshitou_io;

import java.io.FileOutputStream;
import java.io.IOException;

public class Test {

/**
* 使用FileOutputStream来写入文件
* @throws IOException
*
*/
public static void main(String[] args) throws IOException {
// 创建FileOutputStream对象
// write.txt 文件在项目的根目录下面
FileOutputStream fos = new FileOutputStream("write.txt");
// 准备byte数组
byte[] b = "Hello every body!".getBytes();

// 写入整个数组
fos.write(b);
// 写入换行符,System.lineSeparator()方法返回一个字符串,表示跨平台的换行符
fos.write(System.lineSeparator().getBytes());
// 写入数组的一部分
fos.write(b, 0, 5);// 应该写入的是Hello

// 关闭输出流
fos.close();
// 文件的内容为:
/*
Hello every body!
Hello
*/

}

}


如果写入的文件存在,会被覆盖掉;要想在文件的末尾进行追加内容(保留以前的内容),就需要在创建FileOutputStream对象是,向构造器传入一个true;下面演示向文件中追加内容:

package com.xiaoshitou_io;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {

/**
* 使用FileOutputStream来写入文件
* 直接在Write.txt文件追加内容
* @throws IOException
*
*/
public static void main(String[] args) throws IOException {
// 创建FileOutputStream对象
// write.txt 文件在项目的根目录下面

File writeFile = new File("write.txt");
// 在创建对象传入一个true
FileOutputStream fos = new FileOutputStream(writeFile, true);
// 准备byte数组
byte[] b = (System.lineSeparator()+"我是追加的内容,哈哈").getBytes();
// 写入文件
fos.write(b);

// 关闭输出流
fos.close();
// 文件的内容为:
/*
Hello every body!
Hello
我是追加的内容,哈哈
*/

}

}


InputStream:

  进行文件的读取经常使用的是InputStream的子类,FileInputStream可以读取任何文件,经常用的方法就是直接读入一个byte数组,这样是为了提高读取效率,不是用一个一个字节的读取。

  下面演示一个文件的复制,文件的复制,就是利用字节输入流读取文件,然后利用输出流写入文件。下面是复制一个视频文件(同时用了输入流和输出流):

package com.xiaoshitou_io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {

/**
* 将C:\Users\Beck\Desktop\temp目录下all.avi文件复制到
* 当前文件中,名字为copy.avi
*/
public static void main(String[] args){
// 创建输入输出流
FileInputStream fis = null;
FileOutputStream fos = null;
try{
File file = new File("C:/Users/Beck/Desktop/temp");
fis = new FileInputStream(new File(file, "all.avi"));
fos = new FileOutputStream(new File(file, "copy.avi"));
// 进行读写操作
int len = -1;
// 每次读入1M
byte[] b = new byte[1024*1024];
while ((len=fis.read(b)) != -1){
// 写入
fos.write(b, 0, len);
}

}catch (IOException e){
e.printStackTrace();
throw new RuntimeException("文件复制失败!");
}finally{
// 关闭流对象
try{
if (fos != null){
fos.close();
}
}catch (IOException e){
e.printStackTrace();
throw new RuntimeException("释放资源失败!");
}finally{
try{
if (fis != null){
fis.close();
}
}catch (IOException e){
e.printStackTrace();
throw new RuntimeException("释放资源失败!");
}
}
}
System.out.println("复制文件完毕!");
// 输出结果:
/*复制文件完毕!*/
}

}


BufferedInputStream&BufferedOutputStream:

  字符缓冲输入流和字符缓冲输出流,这两个流的作用的是提高输入输出的效率。BufferedInputStream&BufferedOutputStream,接收的参数分别是InputStream,OutputStream,底层还是利用字节的输入输出流,只是对输入输出流进行了封装。

  下面利用BufferedInputStream&BufferedOutputStream进行文件的复制:

package com.xiaoshitou_io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {

/**
* 将C:\Users\Beck\Desktop\temp目录下all.avi文件复制到
* 当前文件中,名字为copy.avi
* 这次使用的是BufferedInputStream 和 BufferedOutputStream来完成
*/
public static void main(String[] args){
// 创建缓冲输入输出流
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try{
File file = new File("C:/Users/Beck/Desktop/temp");
bis = new BufferedInputStream(new FileInputStream(new File(file, "all.avi")));
bos = new BufferedOutputStream(new FileOutputStream(new File(file, "copy.avi")));
// 进行读写操作
int len = -1;
// 每次读入1M
byte[] b = new byte[1024*1024];
while ((len=bis.read(b)) != -1){
// 写入
bos.write(b, 0, len);
}

}catch (IOException e){
e.printStackTrace();
throw new RuntimeException("文件复制失败!");
}finally{
// 关闭流对象
try{
if (bos != null){
bos.close();
}
}catch (IOException e){
e.printStackTrace();
throw new RuntimeException("释放资源失败!");
}finally{
try{
if (bis != null){
bis.close();
}
}catch (IOException e){
e.printStackTrace();
throw new RuntimeException("释放资源失败!");
}
}
}
System.out.println("复制文件完毕!");
// 输出结果:
/*复制文件完毕!*/
}

}


练习:把一个视频文件按照5M的大小切割成多个。

package com.xiaoshitou_io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Test {

/**
* 将C:\Users\Beck\Desktop\temp目录下all.avi文件复制到
* 这次是把all.avi视频文件切割成多个文件。按照每个文件5M的大小切割
* @throws IOException
*/
public static void main(String[] args) throws IOException{
// 这次我把IOException直接抛出去了没有捕获
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream("C:/Users/Beck/Desktop/temp/all.avi"));
// 读取视频文件
int len = -1;
// 每次读入5M
byte[] bytes = new byte[1024*1024*5];
int flag = 0;
while ((len=bis.read(bytes)) != -1 ){
flag++;
// 把读入的文件写入到一个文件中
writeToFile(bytes, len, flag);
}
// 关闭输入流
bis.close();
System.out.println("切割完成!");

}

// 将一个byte数组的内容写入到一个文件中
private static void writeToFile(byte[] bytes, int len, int flag) throws IOException {
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("C:/Users/Beck/Desktop/temp/copy_"+flag+".avi"));
bos.write(bytes, 0, len);
bos.close();
}
}


  切割结果:



字符流:

输出流:Writer

输入流:Reader

字符流的底层是字节流+编码表

字符流只能操作文本文件,进行文本文件的读写,如果是为了复制文件的话,最好选择字节流进行复制。

Writer:

Writer下面有两个常用的字符输出流:OutputStreamWriter和FileWriter

OutputStreamWriter:接收的参数是一个OutputStream参数,也可以传一个charset编码字符串,这样就可以按照你设置的编码写入文本文件中。

以utf-8编码形式向文本文件中写入内容:

package com.xiaoshitou_io;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class Test {
/*
* 以utf8的格式向文件中写入字符串
*/
public static void main(String[] args) throws IOException{
// 创建 OutputStreamWriter对象
OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("wirter.txt"),"utf-8");

osw.write("我是OutputStreamWriter写入的,");
osw.write("我的编码是UTF-8格式的。");
// 字符流需要自己刷新
osw.flush();
// 关闭流
osw.close();
//输出结果,两句话在一行,因为没有写入换行符
/*
我是OutputStreamWriter写入的,我的编码是UTF-8格式的。
*/

}

}


FileWriter:可以接收的参数可以是File对象或者是String类型的;它的编码是系统默认的编码,我们的一般编码是使用的是GBK编码。

使用FileWriter向文本文件中写入字符串:

package com.xiaoshitou_io;

import java.io.FileWriter;
import java.io.IOException;

public class Test {
/*
* 用FileWriter向文件中写入内容
*/
public static void main(String[] args) throws IOException{
// 创建 FileWriter对象
FileWriter fw = new FileWriter("writer_gbk.txt");

fw.write("我是用FileWriter写的");
// 写入换行符
fw.write(System.lineSeparator());
fw.write("我的编码是用的是默认的,GBK");
fw.flush();

// 关闭流
fw.close();
// 输出结果
/*
我是用FileWriter写的
我的编码是用的是默认的,GBK
*/

}

}


Reader:

Reader下面有两个常用的字符流:InputStreamReader,FileReader

InputStreamReader:可以按照指定的编码去读取文本文件,接收的参数是InputStream和一个编码字符串。

以utf-8的编码去读取一个文本文件:

package com.xiaoshitou_io;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class Test {
/*
* 以UTF-8去读取writer.txt
* 这个文件是刚才用utf-8的格式写入的,
* 也只能以utf8的格式去读取,否则会出现乱码
*/
public static void main(String[] args) throws IOException{
// 创建InputStreamReader对象
InputStreamReader isr = new InputStreamReader(new FileInputStream("wirter.txt"), "utf-8");

int len = -1;
// 一次可以读取1024个字符,2*1024个字节,2KB
char[] ch = new char[1024];
while ((len=isr.read(ch)) != -1){
System.out.print(new String(ch, 0, len));
}
// 关闭流
isr.close();
// 输出结果:
/*
我是OutputStreamWriter写入的,我的编码是UTF-8格式的。
*/
}

}


FileReader:以系统默认的编码去读取一个文本文件。接收的参数可以是一个File或者String。

用FileReader去读取GBK的文件,系统默认的编码是GBK

package com.xiaoshitou_io;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class Test {
/*
* 用FileReader来读取文件writer_gbk.txt
* FileReader默认是用的是系统的默认编码
* 本机的默认编码是GBK
*/
public static void main(String[] args) throws IOException{
// 创建FileReader对象
FileReader fr = new FileReader(new File("writer_gbk.txt"));

int len = -1;
char[] ch = new char[1024];
while ((len=fr.read(ch)) != -1){
System.out.println(new String(ch,0,len));
}

// 关闭流
fr.close();
// 输出结果
/*
我是用FileWriter写的
我的编码是用的是默认的,GBK
*/

}

}


乱码:

乱码产生的原因:用一个A编码表将字符转成字节, 又用B编码表将字节转回字符. 两个编码表对应的关系不同,因此查到的结果就不同.

保证不乱码的方式 : 编码与解码保持相同.

字符流复制文件原理:





BufferedReader&BufferedWriter:

BufferedReader&BufferedWriter:字符缓冲输入输出流,接收的参数分别是:Reader,Writer;作用是提高读写的速度,读写时字符的编码是系统默认的编码:

BufferedReader特有的一个方式读取一行readLine(),不会读取换行符

BufferedWrter特有的一个方法时,newLine()写入一个换行符

在写入的数据之后,需要手动flush。

利用BufferedReader&BufferedWriter进行文本文件的读写:

package com.xiaoshitou_io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Test {
/*
* 利用BufferedReader&BufferedWriter进行文本文件的读写:
* 复制文件:test.properties
*/
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new FileReader("test.properties"));
BufferedWriter bw = new BufferedWriter(new FileWriter("test_copy.properties"));

// 进行读写,缓冲流特有的方法就是可以按照行来读取,如果读取结束返回null
String line = null;
while ((line=br.readLine()) != null){
bw.write(line);
// 写入换行
bw.newLine();
// 刷新
bw.flush();
}

// 关闭流
bw.close();
br.close();

}

}


字节流和字符流的总结:





  IO流只能操作文件”文件”,不能操作文件夹(目录),否则会出现异常。

打印流:

  PrintStream,PrintWriter:字节打印流,字符打印流;打印流只有输出流,没有输入流;输出的目的可以是文件,也可以是其他流。PrintStream自带刷新功能,PrintWriter需要手动开启。

  PrintStream:打印出来的字符的编码使用的是系统默认编码。

package com.xiaoshitou_io;

import java.io.IOException;
import java.io.PrintStream;

public class Test {
/*
* 使用打印流:PrintStream
*/
public static void main(String[] args) throws IOException{

PrintStream ps = new PrintStream("print.txt");
ps.println("旺旺");
ps.println("欢欢");
ps.println("乐乐");
ps.close();
// 结果:
/*
旺旺
欢欢
乐乐
*/
}

}


  PrintWriter:

package com.xiaoshitou_io;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class Test {
/*
* 使用打印流:PrintWriter
*/
public static void main(String[] args) throws IOException{
// 创建PrintWriter对象时,开启自动刷新功能
PrintWriter pw = new PrintWriter(new FileWriter("print.txt"), true);

pw.println("我是PrintWriter");
pw.println("出来的");

pw.close();
// 结果:
/*
我是PrintWriter
出来的
*/
}

}


序列化&反序列化:

序列化:就是将对象写入文件的过程

反序列化:从文件读入对象的过程

ObjectOutputStream&ObjectInputStream:需要序列化的对象必须去实现Serializable接口,否则在序列化的时候会出错。

序列化的注意点:

1、static修饰的成员不能被序列化

2、要想成员变量不被序列化,可以用transient关键字修饰

3、为了不发生序列号冲突,设置:serialVersionUID

下面就进行序列化和反序列化:

package com.xiaoshitou_io;

import java.io.Serializable;

public class Student implements Serializable{
private static final long serialVersionUID = -5214244848175027425L;
private String name;
private String id;
private transient String phone;

public Student(String name, String id, String phone) {
super();
this.name = name;
this.id = id;
this.phone = phone;
}
public Student() {
super();

}

@Override
public String toString() {
return "Student [name=" + name + ", id=" + id + ", phone=" + phone
+ "]";
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}

}

package com.xiaoshitou_io;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Test {
/*
* 进行序列化和反序列化
* 对Student对象序列化
*/
public static void main(String[] args) throws IOException, ClassNotFoundException{
// 创建ObjectOutputStream对象,绑定目的地
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("tmp.txt"));
// 创建Student对象
Student stu = new Student("张三", "T001", "15522223333");
// 写入对象
oos.writeObject(stu);
// 关闭流
oos.close();
System.out.println("序列化成功!");
System.out.println("==============分割==============");

// 进行反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("tmp.txt"));
// 读取对象
Object obj = ois.readObject();
if (obj instanceof Student){
Student s = (Student)obj;
System.out.println(s);
}
// 关闭流
ois.close();
System.out.println("反序列化成功!");
// 结果:phone是transient关键字修饰的,所以没有被序列化
/*
序列化成功!
==============分割==============
Student [name=张三, id=T001, phone=null]
反序列化成功!
*/

}

}


Properties:

Properties类是HashTable的一个子类,实现了Map接口,所以里面保存的是键值对,元素的存取是无序的,这个类经常被用来处理配置文件。

利用Properties来读写文件:

package com.xiaoshitou_io;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class Test {
/*
* 利用Properties来读写文件
*/
public static void main(String[] args) throws IOException{
// 读取Properties文件:pro.properties
Properties pro = new Properties();
// 加载文件
pro.load(new FileReader("pro.properties"));
// 根据key来读取值
String key = pro.getProperty("key");
System.out.println(key);
String value = pro.getProperty("匿名");
System.out.println(value);
System.out.println("=============================");

// 修改Properties内的值,或者添加新的值
pro.setProperty("key", "我是修改的值");
pro.setProperty("add", "我是新添加的值");
// 保存进文件
pro.store(new FileWriter("pro.properties"),"");
System.out.println("修改完成");
// 控制台打印结果:
/*
姥姥阿里
娇娇
=============================
修改完成
*/
// pro.properties 文件中的内容:
/*
#
#Sun Jun 11 08:53:22 CST 2017
key=我是修改的值
张嘴=监控
匿名=娇娇
add=我是新添加的值
*/
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: