IO流基本知识

使用File类执行的所有操作都是针对于文件本身,但是却没有针对于文件的内容,而要进行文件内容操作就需要通过Java之中提供的两组类完成:
• 字节操作流(是在JDK 1.0的时候定义的):OutputStream、InputStream;
• 字符操作流(是在JDK 1.1的时候定义的):Writer、Reader。

但是不管是字节流还是字符流的操作,本身都表示资源操作,而执行所有的资源操作都会按照如下的几个步骤进行,下面以文件操作为例(对文件进行读、写操作):

• 如果要操作的是文件,那么首先要通过File类对象找到一个要操作的文件路径(路径有可能存在,有可能不存在,如果不存在,则要创建路径);
• 通过字节流或字符流的子类为字节流或字符流的对象实例化(向上转型);
• 执行读 / 写操作;
• 最后一定要关闭操作的资源(close()),不管日后如何操作,资源永远要关闭。

java.io.OutputStream主要的功能是进行字节数据的输出的,而这个类的定义如下:

public abstract class OutputStream
extends Object
implements Closeable, Flushable

发现OutputStream类定义的时候实现了两个接口:Closeable、Flushable,那么这两个接口的定义如下:
Closeable:JDK 1.5推出 Flushable:JDK 1.5推出

public interface Closeable extendsAutoCloseable {
public void close() throws IOException;
}
public interface Flushable {
public void flush() throws IOException;
}


• 实例化FileOutputStream(新建数据):public FileOutputStream(File file) throws FileNotFoundException;
• 实例化FileOutputStream(追加数据):public FileOutputStream(File file, boolean append)
throws FileNotFoundException

public class TestDemo {
    public static void main(String[] args) throws Exception {
        File file = new File("D:" + File.separator + "hellodemo"
                + File.separator + "test.txt"); // 第1步:定义文件路径
        if (!file.getParentFile().exists()) { // 父路径不存在
            file.getParentFile().mkdirs(); // 创建父路径
        }   
        OutputStream output = new FileOutputStream(file); // 第2步:通过子类实例化父类
        String data = "Hello World .";// 要输出的数据
        output.write(data.getBytes()); // 第3步:输出数据,要将数据变为字节数组输出
        output.close(); // 第4步:关闭资源
    }
}

如果现在要输出的文件不存在,那么会出现自动创建文件的情况,并且如果重复执行以上的代码,会出现新的内容覆盖掉旧内容的操作,所以下面可以使用FileOutputStream类的另外一个构造方法进行数据的追加:

public class TestDemo {
    public static void main(String[] args) throws Exception {
        File file = new File("D:" + File.separator + "hellodemo"
                + File.separator + "test.txt"); // 第1步:定义文件路径
        if (!file.getParentFile().exists()) { // 父路径不存在
            file.getParentFile().mkdirs(); // 创建父路径
        }
        OutputStream output = new FileOutputStream(file, true);// 第2步:通过子类实例化父类
        String data = "Hello World .\r\n";// 要输出的数据
        output.write(data.getBytes()); // 第3步:输出数据,要将数据变为字节数组输出
        output.close(); // 第4步:关闭资源
    }
}

在Wirter类之中定义的write()方法都是以字符数据为主,但是在这些方法之中,只关心一个:
• 输出一个字符串:public void write(String str) throws IOException。
在Wirter类之中比OutputStream类最为方便的一点就是其可以直接使用String型数据输出

public class TestDemo {
    public static void main(String[] args) throws Exception {
        File file = new File("D:" + File.separator + "hellodemo"
                + File.separator + "test.txt"); // 定义文件路径
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();// 创建父目录
        }   
        Writer out = new FileWriter(file);
        String data = "Hello World .";
        out.write(data) ;   // 直接输出字符串
        out.close() ;   // 关闭输出
    }
}

如果现在要从指定的数据源之中读取数据,使用InputStream,而这个类的定义如下:
public abstract class InputStream extends Object
implements Closeable
在InputStream类之中,定义了三个读取数据的操作方法:

• 读取单个字节:public abstract int read() throws IOException;
|- 说明:每次执行read()方法都会读取一个数据源的指定数据,如果现在发现已经读取到了结尾返回-1;
• 读取多个字节:public int read(byte[] b) throws IOException;
|- 说明:如果现在要读取的数据小于byte的数据,这个时候read()方法的返回值int返回的是数据个数,如果现在开辟的字节数组小于读取的长度,如果数据已经读完了,则这个时候的int返回的是-1;
• 读取指定多个字节:public int read(byte[] b, int off, int len) throws IOException。


InputStream基本方法
三个基本的read方法:
int read()
从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1 。
int read(byte[] buffer)
从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。以整数形式返回实际读取的字节数。
int read(byte[] buffer, int offset, int len)
将输入流中最多 len 个数据字节读入 byte 数组。尝试读取 len 个字节,但读取的字节也可能小于该值。以整数形式返回实际读取的字节数。

public class TestDemo {
    public static void main(String[] args) throws Exception {
        File file = new File("D:" + File.separator + "hellodemo"
                + File.separator + "test.txt"); // 定义文件路径
        if (file.exists()) {    // 文件存在则可以读取
            InputStream input = new FileInputStream(file) ;
            byte data[] = new byte[1024]; // 假设要读的长度是1024
            int len = input.read(data) ;    // 读取数据,返回读取个数
            input.close() ; // 关闭
            System.out.println("读取的数据是:【" + new String(data, 0, len) + "】");
        }
    }
}

在使用手机的过程之中短信功能就是这种操作,每一个短信只能发送70个字,不管是否够70都按70算,因为接收短信的时候是开辟了一个指定长度的空间进行接收。


重点:
如果现在某个操作必须发生IO,但是又不希望有一些临时文件产生的话,那么现在肯定无法使用之前的文件操作流,所以为了解决这样的问题,提供了内存操作流,即:以内存进行操作的终端,以发生IO操作关系。
对于内存操作流也是分为两组:
• 字节内存操作流:内存输入流(ByteArrayInputStream)、内存输出流(ByteArrayOutputStream);
• 字符内存操作流:内存输入流(CharArrayReader)、内存输出流(CharArrayWriter)。

public class TestDemo {
    public static void main(String[] args) throws Exception {
        String str = "hello world ."; // 有非字母组成
        InputStream input = new ByteArrayInputStream(str.getBytes()); // 将数据输出到内存之中
        OutputStream output = new ByteArrayOutputStream(); // 准备从内存之中读取数据
        int temp = 0;
        while ((temp = input.read()) != -1) {
            output.write((char) Character.toUpperCase(temp)); // 所有内容都在字节输出流中
        }
        String newStr = output.toString(); // 取数据
        output.close();
        input.close();
        System.out.println(newStr);
    }
}

打印流
两个类:字节打印流类(PrintStream)、字符打印流类(PrintWriter),现在还是以字节打印流为主,而字符打印流主要是可以方便的输出中文。

public class TestDemo {
    public static void main(String[] args) throws Exception {
        String str = "hello world ."; // 有非字母组成
        InputStream input = new ByteArrayInputStream(str.getBytes()); // 将数据输出到内存之中
        OutputStream output = new ByteArrayOutputStream(); // 准备从内存之中读取数据
        PrintStream out = new PrintStream(output) ; // 使用打印流间接调用了内存输出流
        int temp = 0;
        while ((temp = input.read()) != -1) {
            out.print((char) Character.toUpperCase(temp)); // 所有内容都在字节输出流中
        }
        String newStr = output.toString(); // 取数据
        output.close();
        input.close();
        System.out.println(newStr);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值