IO流

File类

IO流操作中大部分都是对文件的操作,我们想要实现IO的操作,就必须知道硬盘上文件的表现形式,所以Java就提供了File类供我们来操作文件。

File 类可以用于表示文件和目录的信息,但是它不表示文件的内容。

在计算机系统中,文件是非常重要的存储方式。Java的标准库 java.io 提供了File对象来操作文件和目录。

要构造一个File对象,需要传入文件路径:

import java.io.File;

public class FileDemo {
	public static void main(String[] args) {
		File f = new File("D:\\Windows\\a.exe");
		System.out.println(f);
	}
}

构造File对象时,既可以传入绝对路径,也可以传入相对路径。

file类的构造方法有3种

file类的功能:

  • 创建功能:
  • 删除功能:
  • 重命名功能:
  • 判断功能:
  • 获取功能:
  • 高级获取功能;
  • 过滤器功能:

IO流:用来处理设备之间的数据传输。(上传和下载文件)

java中IO流的基类

输入流:读取数据;输出流:写出数据。

  • 字节输入流:InputStream
  • 字节输出流:OutputStream
  • 字符输入流:Reader
  • 字符输出流:Writer

 由于基类都是abstrac类,所以要有具体的子类。

在IO流操作中,最后一定要释放资源(close() ):

在计算机中,类似文件、网络端口这些资源,都是由操作系统统一管理的。应用程序在运行的过程中,如果打开了一个文件进行读写,完成后要及时地关闭,以便让操作系统把资源释放掉,否则,应用程序占用的资源会越来越多,不但白白占用内存,还会影响其他应用程序的运行。

  • 让流对象变成垃圾,被垃圾回收站回收;
  • 通知系统去释放跟该文件相关的资源(因为是系统帮我们创建的文件)。

 小细节:在windows系统中换行是\r\n;Linux中是\n;Mac中是\r。

InputStream

InputStream就是Java标准库提供的最基本的输入流。它位于java.io这个包里。java.io包提供了所有同步IO的功能。要特别注意的一点是,InputStream并不是一个接口,而是一个抽象类,它是所有输入流的超类。这个抽象类定义的一个最重要的方法就是int read().

FileInputStreamInputStream的一个子类。FileInputStream就是从文件流中读取数据。

public static void main(String[] args) throws IOException {
    //创建对象
    FileInputStream in = new FileInputStream("in.txt");
    //读取数据:一次读取一个字节
    int b = 0;
    while((in.read()) != -1) {
        System.out.print((char)b);
    }
		    
    //一次读取一个字节数组
    byte[] by = new byte[1024];
    int len = 0;
    while((len=in.read(by)) != -1) {
        System.out.println(new String(by,0,len));
    }

    //释放资源
    in.close();
}

我们还要注意到在读取或写入IO流的过程中,可能会发生错误,例如,文件不存在导致无法读取,没有写权限导致写入失败,等等,这些底层错误由Java虚拟机自动封装成IOException异常并抛出。因此,所有与IO操作相关的代码都必须正确处理IOException

OutputStream

InputStream相反,OutputStream是Java标准库提供的最基本的输出流。和InputStream类似,OutputStream也是抽象类,它是所有输出流的超类。这个抽象类定义的一个最重要的方法就是void write(int b)

FileOutputStream可以从文件获取输出流,这是OutputStream常用的一个实现类。

实现文件复制:

public class CopyDemo {

	public static void main(String[] args) throws IOException {
        // 创建字节输入流对象
        FileInputStream in = new FileInputStream("a.txt");
        // 创建字节输出流对象
        FileOutputStream out = new FileOutputStream("b.txt");

        // 创建byte对象数组
        byte[] by = new byte[1024];
        // read() 最多读取 by.length 个字节
        // 返回的是实际读取的个数
        // 返回 -1 的时候表示读到 eof,即文件尾
        int len = 0;
        while ((len = in.read(by)) != -1) {
            out.write(by, 0, len);
        }
        // 释放资源
        in.close();
        out.close();
    }
}

字节缓冲流

缓冲区类(高效类):

  • BufferedInputStream
  • BufferedOutputStream

 BufferedOutputStream(OutputStream out):为什么不传递一个具体的文件或者文件路径,而是传递一个OutputStream对象呢?原因就是:字节缓冲区流仅仅提供字节缓冲区,为高效而设计的,真正的读写操作还是要靠基本的流对象实现。

public class BufferDemo2 {
    public static void main(String[] args) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(
            new FileInputStream("a.txt"));
        //读数据
        byte[] by = new byte[1024];
        int len = 0;
        while((len=bis.read(by))!=-1) {
            System.out.print(new String(by,0,len));
        }
        //释放资源
        bis.close();
    }
}

Reader

Windows系统的默认编码可能是GBK。

Reader是Java的IO库提供的另一个输入流接口。和InputStream的区别是,InputStream是一个字节流,即以byte为单位读取,而Reader是一个字符流,即以char为单位读取。
java.io.Reader是所有字符输入流的超类,它最主要的方法是:

public int read() throws IOException;

这个方法读取字符流的下一个字符,并返回字符表示的int,范围是0~65535。如果已读到末尾,返回-1

FileReaderReader的一个子类,它可以打开文件并获取Reader

Writer

Reader是带编码转换器的InputStream,它把byte转换为char,而Writer就是带编码转换器的OutputStream,它把char转换为byte并输出。

FileWriter就是向文件中写入字符流的Writer

public class CopyDemo2 {

	public static void main(String[] args) throws IOException {
		//封装数据源
		FileReader in = new FileReader("a.txt");
		//封装目的地
		FileWriter out = new FileWriter("b.txt");
		
		//读写数据
		char[] ch = new char[1024];
		int len = 0;
		while((len=in.read(ch)) != -1) {
			out.write(ch, 0, len);
			out.flush();
		}
		
		//关闭
		in.close();
		out.close();
	}
}

String的编码方式

/*
 * String 可以看成一个字符序列,
 * 可以指定一个编码方式将它编码为字节序列,
 * 也可以指定一个编码方式将一个字节序列解码为 String。
 */
public class Test {
	
    public static void main(String[] args) {
        //String -- byte[]
        String str1 = "无敌敏";
        byte[] by = str1.getBytes();
		
        //byte[] -- String
        String str2 = new String(by);
        System.out.println(str2);
    }
}

字符缓冲流

BufferedReader:readLine():一次读取一行数据;

BufferedWriter:newLine():写入一个行分隔符。

public static void main(String[] args) throws IOException {
    //封装数据源
    BufferedReader in = new BufferedReader(new FileReader("a.txt"));
    //封装目的地
    BufferedWriter out = new BufferedWriter(new FileWriter("b.txt"));

    String line = null;
    while((line=in.readLine()) != null) {
        out.write(line);
        out.newLine();
        out.flush();
}
    //关闭
    in.close();
    out.close();
}

打印流

字节打印流:PrintStream

字符打印流:PrintWriter

PrintStream最终输出的总是byte数据,而PrintWriter则是扩展了Writer接口,它的print()/println()方法最终输出的是char数据。

public static void main(String[] args) throws IOException {
    //封装数据源
    BufferedReader in = new BufferedReader(new FileReader("a.txt"));
    //封装目的地(打印流)  true:启动自动刷新
    PrintWriter out = new PrintWriter(new FileWriter("b.txt"),true);

    String line = null;
    while((line=in.readLine()) != null) {
        //println等价于out.write(line);out.newline();out.flush();
        out.println(line);
    }
    //关闭
    in.close();
    out.close();
}

序列化

序列化是指把一个Java对象变成二进制内容,本质上就是一个byte[]数组。

为什么要把Java对象序列化呢?因为序列化后可以把byte[]保存到文件中,或者把byte[]通过网络传输到远程,这样,就相当于把Java对象存储到文件或者通过网络传输出去了。

序列化就是将一个对象转换成字节序列,方便存储和传输。

  • 序列化:ObjectOutputStream.writeObject()
  • 反序列化:ObjectInputStream.readObject()

不会对静态变量进行序列化,因为序列化只是保存对象的状态,静态变量属于类的状态。

一个Java对象要能序列化,必须实现一个特殊的java.io.Serializable接口,它只是一个标准,没有任何方法需要实现,但是如果不去实现它的话而进行序列化,会抛出异常。(我们把这样的空接口称为“标记接口”)

private class A implements Serializable{

}

 序列化和反序列化实例:

public static void main(String[] args) throws IOException, ClassNotFoundException {

    A a1 = new A(123, "abc");

    ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("a.txt"));
    objectOutputStream.writeObject(a1);
    objectOutputStream.close();

    ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("a.txt"));
    A a2 = (A) objectInputStream.readObject();
    objectInputStream.close();
    System.out.println(a2);
}

private static class A implements Serializable {

    private int x;
    private String y;

    A(int x, String y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public String toString() {
        return "x = " + x + "  " + "y = " + y;
    }
}

transient 关键字可以使一些属性不会被序列化。

ArrayList 中存储数据的数组 elementData 是用 transient 修饰的,因为这个数组是动态扩展的,并不是所有的空间都被使用,因此就不需要所有的内容都被序列化。通过重写序列化和反序列化方法,使得可以只序列化数组中有内容的那部分数据。

private transient Object[] elementData;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值