Java基础(IO输入输出流,读写文件操作,对象序列化)

IO

输入输出流基本概念

输入流:信息从程序空间之外的地方流入程序空间里面

输出流:信息从程序空间里面流到程序空间之外的地方

输入输出流的分类

  • 从流的方法划分

    • 输入流
    • 输入流
  • 从流的分工划分

    • 节点流:访问文件进行输入输出操作的流
    • 处理流:在节点流的基础之上对信息进行加工转换处理的流
  • 从流的内容划分

    • 面向字符的流:专门处理字符数据
    • 面向字节的流:用于一般目的即输入输出

Java基础(IO输入输出流,读写文件操作,对象序列化)_第1张图片

所有的输入输出流类都继承于以上四个类

  • 面向字符的流的超类为Reader&Writer

  • 面向字节的流的超类为InputStream&OutputStream

举一个简单的例子,复制一个文件的内容到另一个文件中

首先在该项目的文件所在位置新建一个Redirecting.txt文件

import java.io.*;

public class Redirecting {
    public static void main(String[] args) throws FileNotFoundException {
        BufferedInputStream in = new BufferedInputStream(
                new FileInputStream("Redirecting.txt")); 
        //FileInputStream就是一个面向字节的流,然后再通过BufferedInputStream来转化,
        //BufferedInputStream也是一个流,是一个缓冲流
        PrintStream out = new PrintStream(new
                BufferedOutputStream(new FileOutputStream("test.txt")));
        System.setIn(in); 
        //将输入流重定向到Redirecting文件中,相当于本来我们是从键盘输入,现在变成从文件来输入
        System.setOut(out);
        //将输出流重定向到test.txt文件中,本来应该是输出到显示器上,现在输出到test文件中
        System.setErr(out);
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        //BufferedReader是一个面向字符的流,因为BufferedReder只处理信息,但是不读取信息
        //因此我们需要用一个InputStreamReader来从文件中读取信息,再由BufferedReader转换
        String s;
	    while((s=br.readLine())!=null)
		    System.out.println(s);
            //因为我们已经输出流定向到test.txt文件中了,所以我们这里相当于复制的操作
	    in.close();
	    out.close();
    }
}

写文本文件

import java.io.*;

public class FileWriterTester {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        String fileName = "Hello.txt";
        FileWriter writer = new FileWriter(fileName);
        writer.write("Hello World!");
        writer.close();
    }
}

如果有大量的信息要写入文件,可以使用BufferedWriter

import java.io.*;

public class FileWriterTester {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        String fileName = "Hello.txt";
        BufferedWriter out = new BufferedWriter(new FileWriter(fileName));
        //跟前面说的一样,BufferedWriter也不直接对文件信息进行读取,它只处文件信息
        //因此我们需要用一个FileWriter来读取文件,再转换为BufferedWriter
        out.write("Hello World!");
        out.newLine(); //跨平台的换行,\n不一定在各个平台都是换行
        out.close();
    }
}

读文本文件

import java.io.*;

public class FileWriterTester {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        String fileName = "Hello.txt";
        BufferedReader in = new BufferedReader(new FileReader(fileName));
        //使用BuffereReader类可以按行读取
        String c = in.readLine();
        while(c!=null)
        {
        	System.out.println(c);
        	c=in.readLine();
        }         	
    }
}

Reader类有一个read方法,返回文件中字符的ASCLL码

import java.io.*;

public class FileWriterTester {

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        String fileName = "Hello.txt";
        FileReader in = new FileReader(fileName);
        //前面的BuffereReader类也有read方法
        int c;
        while((c=in.read())!=-1)
        	System.out.print((char)c);     	
    }
}

写二进制文件

写二进制文件用到的类为DataOutputStream,继承于OutputStream,有一个派生类为FileOutputStream,这一个类只针对输入输出而DataoutPutStream可以写入各种类型的数据

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputstreamTester {

    public static void main(String[] args) throws FileNotFoundException, IOException{
            // TODO Auto-generated method stub
            String fileName = "test.dat";
            DataOutputStream out = new DataOutputStream(
                    new FileOutputStream(fileName));
            //用FileOutputStream转换为DataOutputStream
            out.writeByte(-1);
            out.writeByte(2);
            out.writeInt(5);
            out.writeBytes("Hello World");
            out.close();
        }
    }
}

同理,为了加快写入速度,我们可以使用BufferedOutputStream

DataOutputStream out = new DataOutputStream(
			new BufferedOutputStream(
					new FileOutputStream(fileName)));

读二进制文件

import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputstreamTester {

    public static void main(String[] args) throws FileNotFoundException, IOException{
        // TODO Auto-generated method stub
        String fileName = "test.dat";
        DataOutputStream out = new DataOutputStream(
                new BufferedOutputStream(
                        new FileOutputStream(fileName)));
        out.writeByte(-1);
        out.writeByte(2);
        out.close();
        int sum=0;
        try
        {
            DataInputStream in = new DataInputStream(
                new BufferedInputStream(new FileInputStream("test.dat")));
            //读二进制文件用的是DataInputStream,同时使用BufferedInputStream提高读取速度
            try
            {
                while(true)
                {
                    sum+=in.readUnsignedByte();
                }
                    
            }
            catch(EOFException eof)  //如果读到文件尾,就会抛出异常
            {
                System.out.println("The sum is:"+sum);
                in.close();
            }
        }
        catch(IOException iox) //文件读取的异常
        {
            System.out.println("IO Problems with"+fileName);
        }
    }
}

输出结果为257,因为我们读取的是无符号数in.readUnsignedByte(),如果改成in.readByte(),那么结果就是1

注意: 写二进制文件时,我们一般只在一个文件写入一种类型的数据,而且得用文档记录起来

一个拷贝文件的例子

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyBytes {
    public static void main(String[] args) throws IOException{
        if(args.length!=2)
            return;
        DataInputStream instr;
        DataOutputStream outstr;
        instr = new DataInputStream(new BufferedInputStream
                (new FileInputStream(args[0]))); //源文件
        outstr = new DataOutputStream(new BufferedOutputStream
                (new FileOutputStream(args[1])));//目标文件
        int c;
        try 
        {
            while(true)
            {
                c = instr.readUnsignedByte(); //读取源文件的字符
                outstr.writeByte(c); //写入目标文件中
            }          
        } 
        catch (EOFException eof) //读到文件为抛出异常,关闭文件
        {
            // TODO Auto-generated catch block
            outstr.close();
            instr.close();
            return;
        }
    }
}

这里我们用的是args来传递参数的,顺便说一个args的值从哪里来

  1. 在空白区点击右键(鼠标光标所在的地方),然后找到Run As

Java基础(IO输入输出流,读写文件操作,对象序列化)_第2张图片

  1. 在Arugments里边写入args的参数,由空格分隔

Java基础(IO输入输出流,读写文件操作,对象序列化)_第3张图片

运行之后就能发现文件被复制成功了

File类

File类用于创建文件,比较常用的方法由File.exits(),File.delete()

import java.io.*;
public class FileTester {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        File f = new File("hello.txt");
        if(f.exists())
            f.delete();
        else
            try {
                f.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
}

如果hello.txt文件存在,就会被删除,否则就建立一个新的文件

压缩和解压缩Gzip文件

跟前面的类似,我们使用GZIPInputStreamGZIPOutputStream这两个类来实现

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

public class GZIPTester {

    public static void main(String[] args) throws IOException {
        FileInputStream in = new FileInputStream("Hello.txt");
        GZIPOutputStream out = new GZIPOutputStream(
                new FileOutputStream("test.gz"));
        //使用GZIPOutputStream作为输出流
        System.out.println("Writing compressing file from Hello.txt to test.gz");
        int c;
        while((c=in.read())!=-1)
            out.write(c);
        //一个一个字符的写入
        in.close();
        out.close();
    }
}

解压缩test.gz文件

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

public class GZIPTester {

    public static void main(String[] args) throws IOException {
        FileInputStream in = new FileInputStream("Hello.txt");
        GZIPOutputStream out = new GZIPOutputStream(
                new FileOutputStream("test.gz"));
        System.out.println("Writing compressing file from Hello.txt to test.gz");
        int c;
        while((c=in.read())!=-1)
            out.write(c);
        in.close();
        out.close();
        System.out.println("Reading file from test.gz to monitor");
        BufferedReader in2 = new BufferedReader(new InputStreamReader(
                new GZIPInputStream(new FileInputStream("test.gz"))));
        //使用GZIPInputStream来作为输入流,再使用InputSteamReader来作为面向字节到面向字符的桥梁
        String s;
        while((s=in2.readLine())!=null)
            System.out.println(s);
        //输出解压缩后的文件内容
        in2.close();

也可以通过将压缩文件的内容直接写入文件实现解压缩

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

public class GZIPTester {

    public static void main(String[] args) throws IOException {
        FileInputStream in = new FileInputStream("Hello.txt");
        GZIPOutputStream out = new GZIPOutputStream(
                new FileOutputStream("test.gz"));
        System.out.println("Writing compressing file from Hello.txt to test.gz");
        int c;
        while((c=in.read())!=-1)
            out.write(c);
        in.close();
        out.close();
        System.out.println("Reading file from test.gz to monitor");
        BufferedReader in2 = new BufferedReader(new InputStreamReader(
                new GZIPInputStream(new FileInputStream("test.gz"))));
        String s;
        while((s=in2.readLine())!=null)
            System.out.println(s);
        in2.close();
        System.out.println("Writing decompression to newHello.txt");
        GZIPInputStream in3 = new GZIPInputStream(
                new FileInputStream("test.gz"));
        FileOutputStream out2 = new FileOutputStream("newHello.txt");
        while((c=in3.read())!=-1)
            out2.write(c);
        //一个一个字节的写
        in3.close();
        out2.close(); 
    }
}

也可以把多个文件压缩到一个文件中去,也就是Zip文件

我们使用ZipOutputStream类来实现

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ZipOutputStreamTester {

    public static void main(String[] args) throws IOException {
        ZipOutputStream out = new ZipOutputStream(
                new BufferedOutputStream(
                        new FileOutputStream("test.zip")));
        //使用ZipOutputStream作为输出流
        for(int i=0; i

解压缩Zip文件使用ZipInputStream类来实现

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ZipOutputStreamTester {

    public static void main(String[] args) throws IOException {
        System.out.println("Reading file!");
        ZipInputStream in2 = new ZipInputStream(
                new BufferedInputStream(
                        new FileInputStream("test.zip")));
        //使用ZipInputStream来定义输入流
        ZipEntry ze;
        while((ze=in2.getNextEntry())!=null) //获取文件入口
        {
            System.out.println("Reading file"+ze.getName());
            int x;
            while((x=in2.read())!=-1)
                System.out.write(x);
            //将文件内容输出
            System.out.println();
        }
        in2.close();
    }
}

上面我们只是将压缩文件输出而已,我们更希望将压缩文件解压为一个一个的文件,下面我们来实现这一功能

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class Unzip {
	byte doc[] = null;
	String Filename = null;
	String UnZipPath = null;
	public Unzip(String filename, String unZipPath) //构造函数初始化文件名和压缩路径
	{
		this.Filename = filename;
		this.UnZipPath = unZipPath;
		this.setUnZipPath(this.UnZipPath);
	}
	public Unzip(String filename)
	{
		this.Filename = new String(filename);
		this.UnZipPath = null;
		this.setUnZipPath(this.UnZipPath);
	}
	private void setUnZipPath(String unZipPath)//统一在路径名后面加上\\
	 { 
		if(unZipPath.endsWith("\\"))
			this.UnZipPath=new String(unZipPath);
		else
			this.UnZipPath=new String(unZipPath+"\\");
	}
	public void doUnzip()
	{
		try
		{
			ZipInputStream zipis = new ZipInputStream(
					new FileInputStream(Filename));
			//用ZipInputStream定义输入流
			ZipEntry fEntry = null;
			//文件入口,可以参考前面的压缩文件操作
			while((fEntry=zipis.getNextEntry())!=null)//压缩包中的文件是否解压缩完
			{
				if(fEntry.isDirectory()) //如果文件是一个路径,检查该文件是否存在,不存在就新建
					checkFilePath(UnZipPath+fEntry.getName());
				else
				{
					String fname = new String(UnZipPath+fEntry.getName()); //拼接路径名
					try
					{
						FileOutputStream out = new FileOutputStream(fname);
						doc=new byte[512]; //一次性读取512个字节,加快读取效率
						int n;
						while(((n=zipis.read(doc,0,512))!=-1)) //如果文件没有512字节,那么n就是字节个数
							out.write(doc, 0, n);
						out.close();
						out=null;
						doc=null;
					}
					catch(Exception ex)
					{}
				}
			}
			zipis.close();		
		}
		catch(IOException ioe)
		{
				System.out.println(ioe);
		}
	}
	private void checkFilePath(String dirName) { //检查文件是否存在,不存在就新建
		// TODO Auto-generated method stub
		File dir = new File(dirName);
		if(!dir.exists())
			dir.mkdir();	
	}
	public static void main(String[] args) {
		String zipFile=args[0];
		String unZipPath = args[1]+"\\";
		Unzip myZip=new Unzip(zipFile,unZipPath);
		myZip.doUnzip();
	}
}

ps:如果报错文件夹拒绝访问,可以去属性那里添加用户权限,百度找一下方法

对象序列化

对象序列化就是将对象的值保存到文件中,因为一个对象在程序的存活时间不长

使用的类为ObjectInputStreamObjectOutputStream

  • 不保存对象的transientstatic类型的变量
  • 对象要实现序列化,其所属的类必须实现Serializable接口(Serializable接口只是一个标记,里边没有声明任何方法原型)

下面一个程序实现将一个对象的值存入文件,再读取出来

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

public class SerializableTester {

    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        // TODO Auto-generated method stub
        Book book = new Book(10032,"ComupterNetworking"); 
        //实例化一个对象,Book可以直接定义,在其他文件或同一文件下
        ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("book.dat"));
        //使用ObjectOutputStream作为输出流
        oos.writeObject(book);
        oos.close();
        book = null;
        ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("book.dat"));
        //同上
        book = (Book)ois.readObject(); 
        //readObject可以得到对象的值,注意文件中保存对象的类型必须直接记录
        ois.close();
        System.out.println(book.id);
        System.out.println(book.name);
    }

}
ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("book.dat"));
        //使用ObjectOutputStream作为输出流
        oos.writeObject(book);
        oos.close();
        book = null;
        ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("book.dat"));
        //同上
        book = (Book)ois.readObject(); 
        //readObject可以得到对象的值,注意文件中保存对象的类型必须直接记录
        ois.close();
        System.out.println(book.id);
        System.out.println(book.name);
    }

}

参考

清华大学Java教程p67-p77

你可能感兴趣的:(java,编程语言)