欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

IO之输入字符流FileReader、输出字符FileWriter

程序员文章站 2024-03-18 18:59:04
...
/**

流的分类:
--按流向:输入流、输出流
    理解输入输出流的时候站在程序的角度
    文件-->程序:输入流,读操作
    程序-->文件:输出流,写操作
--按操作数据单位:字节流、字符流
    字节流:一次读取1字节byte=8bit
    字符流:一次读取1字符char=16bit


读取文件操作3个步骤:
1、打开管道(流),装载数据文件
    如果是文本文件,使用字符流
    如果是二进制文件,使用字节流
2、读取文件数据
3、关闭管道(流)
    程序中打开的文件 IO 资源不属于内存里的资源,而是和操作系统相关的资源。垃圾回收机制无法回收该资源,所以应该显式关闭文件 IO 资源。



注意:
脏数据的产生:使用缓冲数组长度进行读写操作,读写到最后数据文件装载不满缓冲数组时,缓冲数组剩余空间会存放上次遗留的数据。

读操作时如果文件名所在路径下不存在该文件则会抛出异常,所以必须指定所在文件路径下存在该文件;而对于写操作如果文件不存在,则会在当前目录下自动创建指定文件名的文件。


写数据2种选择方式:
public FileWriter(String fileName);覆盖写入
public FileWriter(String fileName, boolean append);追加写入


写数据结束时:先刷新,再关闭流
public void flush();
public void close();




*/

========================
FileReader:

/**
    public int read();读单取个字符,返回作为整数读取的字符
    public int read(char buf[]);掌握,将字符读入数组,返回值是读取的字符数
    public int read(char buf[], int off, int len);
    public void close();


*/

读文件数据并在控制台输出代码:

/*
    tips:
    装载数据文件时候路径的选择
    读取数据文件操作的第2个步骤,读取数据文件的几种方式。

*/
package com.zbiti.io.reader;

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

public class FileReader1 {
    public static void main(String[] args) {
        FileReader fileReader = null;
        // 读取文件操作:1打开管道,装载数据文件 2、创建字符数组,循环读取数据文件 3、关闭管道(流)
        try {
            // 打开管道,装载数据文件
            //文件路径:相对于当前目录,即项目路径下
            fileReader = new FileReader("fileinput.txt");


            // 创建字符数组,用来装载一次读取的数据量
            char buf[] = new char[5];
            // 定义一个int类型的realCount用来记录实际读取的字符数,使用缓冲数组循环读取数据文件
            int realCount = 0;
            try {
                //读取的过程中可能抛出io读取异常,需要进行捕获处理
                while ((realCount = fileReader.read(buf)) != -1) {
                    //在控制台打印输出每次循环读取装载进缓冲数组的数据,因为是缓冲数组,所有需要遍历
                    /*

                        循环条件若选择缓冲字符数组长度,有可能会读取到脏数据,假设读取的数据文件有850个字符,
                        使用缓冲字符数组每次装载100个字符并读取,然后在控制台输出,但是循环读取到最后一次,
                        只有50个字符装载进缓冲字符数组,这个时候缓冲字符数组还剩余50个字符装载空间,
                        而这50个字符装载空间是保留上次装载的数据的,是我们不需要的数据的,即所谓的脏数据。

                       for(int i=0;i<buf.length;i++){ 
                        System.out.print(buf[i]);
                    }

                    */
                    for(int i=0;i<realCount;i++){
                        System.out.print(buf[i]);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {

            // 关闭管道,如果管道不为空,才关闭管道,因为有可能打开管道装载数据文件的时候找不到指定文件则会抛出文件找不到异常,被捕获处理,
            // 接着异常捕获处理完毕,最后执行finally块,刚才出现文件找不到异常,管道就是为空的,根本不需要关闭。
            if (fileReader != null) {
                try {
                    // 如果管道不为空,关闭管道,需要再次对受检异常io操作进行处理,在这个过程中有可能关闭管道的时候会出现异常。
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

======================

/*
    编写程序FileReaderTest.java,在main方法中,读取FileReaderTest.java文本文件,并将文件内容输出到屏幕上.
    选做:改进该程序,读取文件内容后,在每行开始加上行号,再连同内容一并输出到屏幕上。
*/

//------------------------------------------------
//代码

FileReader fr = null;
        try {
            // 1创建流对象
            fr = new FileReader("./src/com/atguigu/javase/io/FileReaderTest.java");
            // fr = new FileReader("D:/javasecode/workspace/day18/src/com/atguigu/javase/io/FileReaderTest.java");
            // 2处理数据
            char[] buf = new char[100];
            int realCount = 0; // 用来记录每次读取的实际字符数
            int lineNumber = 1;
            System.out.print(lineNumber++ + " ");
            while ((realCount = fr.read(buf)) != -1) {
                // 处理数据
                for (int i = 0; i < realCount; i++) {
                    System.out.print(buf[i]);
                    if (buf[i] == '\n') {
                        System.out.print(lineNumber++ + " ");
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 3关闭流
            if (fr != null) {
                try {
                    fr.close();
                } catch (Exception e2) {
                }
            }
        }

===============================

FileWriter:

/**
    public void write(int c)
    public void write(char cbuf[]);
    public void write(char cbuf[], int off, int len);掌握
    public void flush();
    public void close();

*/
@Test
    public void testFileWriter() {
        FileWriter fw = null;
        try {
            // 打开流对象,如果文件不存在会自动创建
            fw = new FileWriter("outputFile"); //如果想要以追加的方式写文件  new FileWriter("outputFile", true);
            // 处理数据         
            String[] text = {"这是要写入文件的字符串1\n",
                             "这是要写入文件的字符串2\n",
                             "这是要写入文件的字符串3\n",
                             "这是要写入文件的字符串4\n",
                             "这是要写入文件的字符串5\n",
                             "这是要写入文件的字符串6\n",
                             "这是要写入文件的字符串7\n"};
            for (String line : text) {
                char[] buf = line.toCharArray(); //把字符串对象转换成为相应的字符数组
                //fw.write(buf); // 把数组的内容全部写入输出流
                fw.write(buf, 0, buf.length); //把数组的从下标0开始,总共写全部字符,写入输出流
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭流
            if (fw != null) {
                try {
                    fw.close(); // 输出流调用close()会间接调用到flush().
                } catch (Exception e2) {
                }
            }
        }
    }

========================

/*

练习:
编写程序TextFileCopy.java,在测试方法中,将TextFileCopy.java复制为TextFileCopy.java.bak文件;

*/

未完待续!