JAVA笔记:Java IO流总结
前言
输入输出IO流在Java中,以及众多语言中都是一个很重要的部分,会涉及到系统文件的读取以及其他操作,通过数据流,序列化和文件系统提供系统输入和输出。
在Java类库中,IO部分的内容是很庞大的,因为它涉及的领域很广泛:标准输入输出,文件的操作,网络上的数据流,字符串流,对象流,zip文件流。
java.io包里包含了所有的功能类。
下面用较大的篇幅总结下Java IO(目测是目前博文中的最长篇幅)。
File类
File类可以进行文件的创建或者删除操作。
这里要注意的是操作文件的时候一定要使用分隔符,因为在windows中分隔符是“”,在linux系统中是"/",如果要让系统保持一定的可移植性,则最好根据所在的操作系统来自动使用分隔符。
实例:在F盘下操作文件,如果某文件存在,则删除该文件;如果不存在,则新建一个该文件。
import java.io.File;
public class FlieDemo01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
File file = new File("F:" + File.separator + "test.txt");
if (file.exists()) {
file.delete();
} else {
try {
file.createNewFile();
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}
}
}
}
import java.io.File;
public class FlieDemo01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
File file = new File("F:" + File.separator + "TEST");
try {
file.mkdir();
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}
}
}
列出指定目录的全部文件。
此处有两种方法,1.以字符串数组的形式返回,public String[ ] list();2.以File数组的形式返回public File[ ] listFiles();
第一种:
import java.io.File;
public class FlieDemo01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
File file = new File("F:" + File.separator);
String str[] = file.list();
for (int i = 0; i < str.length; i++) {
System.out.println(str[i]);
}
}
}第二种:import java.awt.List;
import java.io.File;
public class FlieDemo01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
File file = new File("F:" + File.separator);
File files[] = file.listFiles();
for (int i = 0; i < files.length; i++) {
System.out.println(files[i]);
}
}
}第二种列出的是完整的路径:F:$RECYCLE.BIN
F:AndroidWorkPlace
F:Game
F:HBuilderProject
F:MyEclipse workplace
F:TEST
F: est.txt
F:AndroidWorkPlace
F:Game
F:HBuilderProject
F:MyEclipse workplace
F:TEST
F: est.txt
判断给定的路径是否是目录:isDirectory();
RandomAccessFile类
操作时有三种模式: r:只读 w:只写 rw:读写模式,如果此文件不存在,则自动创建。
实例:
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class FlieDemo01 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
File file = new File("F:" + File.separator + "test.txt");
RandomAccessFile rdf = new RandomAccessFile(file, "rw");
String name = null ;
int age = 0 ;
name = "zhangsan" ; // 字符串长度为8
age = 30 ; // 数字的长度为4
rdf.writeBytes(name) ; // 将姓名写入文件之中
rdf.writeInt(age) ; // 将年龄写入文件之中
name = "lisi " ; // 字符串长度为8
age = 31 ; // 数字的长度为4
rdf.writeBytes(name) ; // 将姓名写入文件之中
rdf.writeInt(age) ; // 将年龄写入文件之中
name = "wangwu " ; // 字符串长度为8
age = 32 ; // 数字的长度为4
rdf.writeBytes(name) ; // 将姓名写入文件之中
rdf.writeInt(age) ; // 将年龄写入文件之中
rdf.close() ; // 关闭
}
}
字节流与字符流
流的概念:在程序中所有的数据都是以流的形式传输或者保存的,程序需要数据的时候使用的是输入流,而程序需要将数据保存起来的时候则用的是输出流。
在字节流中输入数据主要是用InputStream,输出用的是OutputStream;而字符流中输入主要是使用Writer类,输出主要是用Reader类。
操作流程:
1.使用File类打开一个文件
2.通过字节流或者字符流的子类,指定输出的位置
3.进行读、写操作
4.关闭输入、输出
IO操作属于资源操作,对于资源操作,操作的最后必须关闭,否则可能出现未知的错误。
字节流实例:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class FlieDemo01 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
File file = new File("F:" + File.separator + "test.txt");
OutputStream out = null;
out = new FileOutputStream(file);
String str = "China PR";
byte b[] = str.getBytes();
out.write(b);
out.close();
}
}
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class FlieDemo01 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
File file = new File("F:" + File.separator + "test.txt");
OutputStream out = null;
out = new FileOutputStream(file,true);//true为是否添加新内容
String str = "gdgdad";
byte b[] = str.getBytes();
out.write(b);
out.close();
}
}
读取文件内容(为了避免空格, 一个一个字符读取):
import java.io.*;
public class FlieDemo01 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
File file = new File("F:" + File.separator + "test.txt");
InputStream in = new FileInputStream(file);
String str = "gdgdad";
byte b[] = new byte[(int) file.length()];
for (int i = 0; i < b.length; i++) {
b[i] = (byte) in.read();
}
in.close();
System.out.println(new String(b));
}
}
字符流实例(写入并可追加):
import java.io.*;
public class FlieDemo01 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
File file = new File("F:" + File.separator + "test.txt");
Writer writer = new FileWriter(file, true);
String str = "China PR wins!";
writer.write(str);
writer.close();
}
}
import java.io.*;
public class FlieDemo01 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
File file = new File("F:" + File.separator + "test.txt");
Reader read = new FileReader(file);
char[] ch = new char[100];
read.read(ch);
read.close();
System.out.println("内容为" + new String(ch));
}
}
最好使用循环读取的方式,因为不知道到底有多少个字节:
import java.io.*;
public class FlieDemo01 {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
File file = new File("F:" + File.separator + "test.txt");
Reader read = new FileReader(file);
char[] ch = new char[100];
int temp = 0;
int count = 0;
while ((temp = read.read()) != -1) {
ch[count++] = (char) temp;
}
read.close();
System.out.println("内容为" + new String(ch));
}
}
字节流和字符流的区别
字节流在使用的时候是不会使用到缓冲区的,它操作的是具体的文件,而字符流在操作的时候是使用缓冲区的,将数据放在缓存中以后,再进行操作。
使用字节流好还是字符流好呢?
答案是字节流。首先因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。但是字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。
答案是字节流。首先因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。但是字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。
OutputStreramWriter 和InputStreamReader类
整个IO类中除了字节流和字符流还包括字节和字符转换流。
OutputStreramWriter将输出的字符流转化为字节流,InputStreamReader将输入的字节流转换为字符流,但是不管如何操作,最后都是以字节的形式保存在文件中的。
实例:将字节输出流转化为字符输出流
import java.io.*;
class hello{
public static void main(String[] args) throws IOException {
String fileName= "d:"+File.separator+"hello.txt";
File file=new File(fileName);
Writer out=new OutputStreamWriter(new FileOutputStream(file));
out.write("hello");
out.close();
}
}
import java.io.*;
class hello{
public static void main(String[] args) throws IOException {
String fileName= "d:"+File.separator+"hello.txt";
File file=new File(fileName);
Reader read=new InputStreamReader(new FileInputStream(file));
char[] b=new char[100];
int len=read.read(b);
System.out.println(new String(b,0,len));
read.close();
}
}
内存操作流
ByteArrayInputStream 主要将内容写入内容,ByteArrayOutputStream 主要将内容从内存输出。
实例:使用内存操作流将一个大写字母转化为小写字母
import java.io.*;
class hello{
public static void main(String[] args) throws IOException {
String str="HELLO";
ByteArrayInputStream input=new ByteArrayInputStream(str.getBytes());
ByteArrayOutputStream output=new ByteArrayOutputStream();
int temp=0;
while((temp=input.read())!=-1){
char ch=(char)temp;
output.write(Character.toLowerCase(ch));
}
String outStr=output.toString();
input.close();
output.close();
System.out.println(outStr);
}
}
管道流
管道流主要可以进行两个线程之间的通信,PipedOutputStream 管道输出流,PipedInputStream 管道输入流。
实例:验证管道流
import java.io.*;
/**
* 消息发送类
* */
class Send implements Runnable{
private PipedOutputStream out=null;
public Send() {
out=new PipedOutputStream();
}
public PipedOutputStream getOut(){
return this.out;
}
public void run(){
String message="hello , Rollen";
try{
out.write(message.getBytes());
}catch (Exception e) {
e.printStackTrace();
}try{
out.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 接受消息类
* */
class Recive implements Runnable{
private PipedInputStream input=null;
public Recive(){
this.input=new PipedInputStream();
}
public PipedInputStream getInput(){
return this.input;
}
public void run(){
byte[] b=new byte[1000];
int len=0;
try{
len=this.input.read(b);
}catch (Exception e) {
e.printStackTrace();
}try{
input.close();
}catch (Exception e) {
e.printStackTrace();
}
System.out.println("接受的内容为 "+(new String(b,0,len)));
}
}
/**
* 测试类
* */
class hello{
public static void main(String[] args) throws IOException {
Send send=new Send();
Recive recive=new Recive();
try{
//管道连接
send.getOut().connect(recive.getInput());
}catch (Exception e) {
e.printStackTrace();
}
new Thread(send).start();
new Thread(recive).start();
}
}
打印流
import java.io.*;
class hello {
public static void main(String[] args) throws IOException {
PrintStream print = new PrintStream(new FileOutputStream(new File("F:"
+ File.separator + "hello.txt")));
print.println(true);
print.println("Hello");
print.close();
}
}
使用OutputStream向屏幕上输出内容
import java.io.*;
class hello {
public static void main(String[] args) throws IOException {
OutputStream out=System.out;
try{
out.write("hello".getBytes());
}catch (Exception e) {
e.printStackTrace();
}
try{
out.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}输入输出重定向
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
/**
* 为System.out.println()重定向输出
* */
public class systemDemo{
public static void main(String[] args){
// 此刻直接输出到屏幕
System.out.println("hello");
File file = new File("d:" + File.separator + "hello.txt");
try{
System.setOut(new PrintStream(new FileOutputStream(file)));
}catch(FileNotFoundException e){
e.printStackTrace();
}
System.out.println("这些内容在文件中才能看到哦!");
}
}
BufferedReader类
BufferedReader只能接受字符流的缓冲区,因为每一个中文需要占据两个字节,所以需要将System.in这个字节输入流变为字符输入流,采用:
实例:
BufferedReader buf = new BufferedReader( new InputStreamReader(System.in));
实例:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* 使用缓冲区从键盘上读入内容
* */
public class BufferedReaderDemo{
public static void main(String[] args){
BufferedReader buf = new BufferedReader(
new InputStreamReader(System.in));
String str = null;
System.out.println("请输入内容");
try{
str = buf.readLine();
}catch(IOException e){
e.printStackTrace();
}
System.out.println("你输入的内容是:" + str);
}
}
Scanner类
其实我们比较常用的是采用Scanner类来进行数据输入,下面来给一个Scanner的例子
import java.util.Scanner;
/**
* Scanner的小例子,从键盘读数据
* */
public class ScannerDemo{
public static void main(String[] args){
Scanner sca = new Scanner(System.in);
// 读一个整数
int temp = sca.nextInt();
System.out.println(temp);
//读取浮点数
float flo=sca.nextFloat();
System.out.println(flo);
//读取字符
//...等等的,都是一些太基础的,就不示例了
}
}使用Scanner读取文件内容import java.io.File;
import java.util.Scanner;
public class BufferedReader01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
File file = new File("F:" + File.separator + "test.txt");
Scanner scanner = null;
try {
scanner = new Scanner(file);
} catch (Exception e) {
// TODO: handle exception
}
String str = scanner.next();
System.out.println(str);
}
}
数据操作流DataOutputStream、DataInputStream类
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataOutputStreamDemo{
public static void main(String[] args) throws IOException{
File file = new File("F:" + File.separator + "hello.txt");
char[] ch = { 'A', 'B', 'C' };
DataOutputStream out = null;
out = new DataOutputStream(new FileOutputStream(file));
for(char temp : ch){
out.writeChar(temp);
}
out.close();
}
}
现在我们在上面例子的基础上,使用DataInputStream读出内容
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class DataOutputStreamDemo{
public static void main(String[] args) throws IOException{
File file = new File("F:" + File.separator + "hello.txt");
DataInputStream input = new DataInputStream(new FileInputStream(file));
char[] ch = new char[10];
int count = 0;
char temp;
while((temp = input.readChar()) != 'C'){
ch[count++] = temp;
}
System.out.println(ch);
}
}
合并流 SequenceInputStream
SequenceInputStream主要用来将2个流合并在一起,比如将两个txt中的内容合并为另外一个txt。
实例:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.SequenceInputStream;
/**
* 将两个文本文件合并为另外一个文本文件
* */
public class SequenceInputStreamDemo{
public static void main(String[] args) throws IOException{
File file1 = new File("F:" + File.separator + "hello1.txt");
File file2 = new File("F:" + File.separator + "hello2.txt");
File file3 = new File("F:" + File.separator + "hello.txt");
InputStream input1 = new FileInputStream(file1);
InputStream input2 = new FileInputStream(file2);
OutputStream output = new FileOutputStream(file3);
// 合并流
SequenceInputStream sis = new SequenceInputStream(input1, input2);
int temp = 0;
while((temp = sis.read()) != -1){
output.write(temp);
}
input1.close();
input2.close();
output.close();
sis.close();
}
}
文件压缩 ZipOutputStream类
压缩单个文件:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipOutputStreamDemo1{
public static void main(String[] args) throws IOException{
File file = new File("F:" + File.separator + "hello.txt");
File zipFile = new File("F:" + File.separator + "hello.zip");
InputStream input = new FileInputStream(file);
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(
zipFile));
zipOut.putNextEntry(new ZipEntry(file.getName()));
// 设置注释
zipOut.setComment("hello");
int temp = 0;
while((temp = input.read()) != -1){
zipOut.write(temp);
}
input.close();
zipOut.close();
}
}压缩多个文件:import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 一次性压缩多个文件
* */
public class ZipOutputStreamDemo2{
public static void main(String[] args) throws IOException{
// 要被压缩的文件夹
File file = new File("F:" + File.separator + "temp");
File zipFile = new File("F:" + File.separator + "zipFile.zip");
InputStream input = null;
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(
zipFile));
zipOut.setComment("hello");
if(file.isDirectory()){
File[] files = file.listFiles();
for(int i = 0; i < files.length; ++i){
input = new FileInputStream(files[i]);
zipOut.putNextEntry(new ZipEntry(file.getName()
+ File.separator + files[i].getName()));
int temp = 0;
while((temp = input.read()) != -1){
zipOut.write(temp);
}
input.close();
}
}
zipOut.close();
}
}
解压缩ZipInputStream类
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
/**
* 解压缩一个压缩文件中包含多个文件的情况
* */
public class ZipFileDemo3{
public static void main(String[] args) throws IOException{
File file = new File("F:" + File.separator + "zipFile.zip");
File outFile = null;
ZipFile zipFile = new ZipFile(file);
ZipInputStream zipInput = new ZipInputStream(new FileInputStream(file));
ZipEntry entry = null;
InputStream input = null;
OutputStream output = null;
while((entry = zipInput.getNextEntry()) != null){
System.out.println("解压缩" + entry.getName() + "文件");
outFile = new File("F:" + File.separator + entry.getName());
if(!outFile.getParentFile().exists()){
outFile.getParentFile().mkdir();
}
if(!outFile.exists()){
outFile.createNewFile();
}
input = zipFile.getInputStream(entry);
output = new FileOutputStream(outFile);
int temp = 0;
while((temp = input.read()) != -1){
output.write(temp);
}
input.close();
output.close();
}
}
}
PushBackInputStream回退流
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.PushbackInputStream;
/**
* 回退流操作
* */
public class PushBackInputStreamDemo{
public static void main(String[] args) throws IOException{
String str = "hello,rollenholt";
PushbackInputStream push = null;
ByteArrayInputStream bat = null;
bat = new ByteArrayInputStream(str.getBytes());
push = new PushbackInputStream(bat);
int temp = 0;
while((temp = push.read()) != -1){
if(temp == ','){
push.unread(temp);
temp = push.read();
System.out.print("(回退" + (char) temp + ") ");
}else{
System.out.print((char) temp);
}
}
}
}
字符编码相关
取得本地编码方式:
public class BufferedReader01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(System.getProperty("file.encoding"));
}
}一般情况下产生乱码,都是由于编码不一致的问题。对象的序列化
对象序列化就是把一个对象变为二进制数据流的一种方法。
一个类要想被序列化,就行必须实现java.io.Serializable接口。虽然这个接口中没有任何方法,就如同之前的cloneable接口一样。实现了这个接口之后,就表示这个类具有被序列化的能力。
先实现一个具有序列化能力的类:
一个类要想被序列化,就行必须实现java.io.Serializable接口。虽然这个接口中没有任何方法,就如同之前的cloneable接口一样。实现了这个接口之后,就表示这个类具有被序列化的能力。
先实现一个具有序列化能力的类:
import java.io.*;
/**
* 实现具有序列化能力的类
* */
public class SerializableDemo implements Serializable{
public SerializableDemo(){
}
public SerializableDemo(String name, int age){
this.name=name;
this.age=age;
}
@Override
public String toString(){
return "姓名:"+name+" 年龄:"+age;
}
private String name;
private int age;
}
ObjectInputStream和ObjectOutputStream类
ObjectInputStream实例:
import java.io.Serializable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
/**
* 实现具有序列化能力的类
* */
public class Person implements Serializable{
public Person(){
}
public Person(String name, int age){
this.name = name;
this.age = age;
}
@Override
public String toString(){
return "姓名:" + name + " 年龄:" + age;
}
private String name;
private int age;
}
/**
* 示范ObjectOutputStream
* */
public class ObjectOutputStreamDemo{
public static void main(String[] args) throws IOException{
File file = new File("d:" + File.separator + "hello.txt");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
file));
oos.writeObject(new Person("rollen", 20));
oos.close();
}
}
Externalizable接口
被Serializable接口声明的类的对象的属性都将被序列化,但是如果想自定义序列化的内容的时候,就需要实现Externalizable接口。当一个类要使用Externalizable这个接口的时候,这个类中必须要有一个无参的构造函数,如果没有的话,在构造的时候会产生异常,这是因为在反序列话的时候会默认调用无参的构造函数。
现在我们来演示一下序列化和反序列化:
import java.io.Externalizable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
/**
* 序列化和反序列化的操作
* */
public class ExternalizableDemo{
public static void main(String[] args) throws Exception{
ser(); // 序列化
dser(); // 反序列话
}
public static void ser() throws Exception{
File file = new File("d:" + File.separator + "hello.txt");
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(
file));
out.writeObject(new Person("rollen", 20));
out.close();
}
public static void dser() throws Exception{
File file = new File("d:" + File.separator + "hello.txt");
ObjectInputStream input = new ObjectInputStream(new FileInputStream(
file));
Object obj = input.readObject();
input.close();
System.out.println(obj);
}
}
class Person implements Externalizable{
public Person(){
}
public Person(String name, int age){
this.name = name;
this.age = age;
}
@Override
public String toString(){
return "姓名:" + name + " 年龄:" + age;
}
// 复写这个方法,根据需要可以保存的属性或者具体内容,在序列化的时候使用
@Override
public void writeExternal(ObjectOutput out) throws IOException{
out.writeObject(this.name);
out.writeInt(age);
}
// 复写这个方法,根据需要读取内容 反序列话的时候需要
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException{
this.name = (String) in.readObject();
this.age = in.readInt();
}
private String name;
private int age;
}
当我们使用Serializable接口实现序列化操作的时候,如果一个对象的某一个属性不想被序列化保存下来,那么可以使用transient关键字进行说明。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* 序列化和反序列化的操作
* */
public class serDemo{
public static void main(String[] args) throws Exception{
ser(); // 序列化
dser(); // 反序列话
}
public static void ser() throws Exception{
File file = new File("d:" + File.separator + "hello.txt");
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(
file));
out.writeObject(new Person1("rollen", 20));
out.close();
}
public static void dser() throws Exception{
File file = new File("d:" + File.separator + "hello.txt");
ObjectInputStream input = new ObjectInputStream(new FileInputStream(
file));
Object obj = input.readObject();
input.close();
System.out.println(obj);
}
}
class Person1 implements Serializable{
public Person1(){
}
public Person1(String name, int age){
this.name = name;
this.age = age;
}
@Override
public String toString(){
return "姓名:" + name + " 年龄:" + age;
}
// 注意这里
private transient String name;
private int age;
}
总结还不够全面,会持续补上。