文件专属流


文章目录

  • 文件专属流
  • FileInputStream流
  • FileInputStream初步读取
  • FileInputStream循环读
  • IDEA默认当前路径
  • 往byte数组中读
  • 最终版FileInputStream流
  • FilleInputStream类的其他方法
  • FileOutputStream流
  • 回顾:
  • 字节流文件的复制
  • FileReader流
  • 代码示例
  • FileWriter流
  • 代码示例:
  • 字符流文件复制


FileInputStream流

FileInputStream初步读取

创建文件字节输入流对象:

FileIputStream  file = new FileInputStream("文件路径")

代码示例:

java.io.FileInputStream:
1.文件字节输入流、万能的,任何类型的文件都可以采用这个流来读
2.字节的方式,完成输入的操作,完成读的操作(硬盘------》内存)

public class FileInputStream01 {

    public static void main(String[] args) {

        FileInputStream stream = null ;

        try {
            //创建文件字节输入流对象
            //以下都是采用了:绝对路径的方式
            //文件路径:E:\Typora笔记\JavaSE\IO流\语录
            //采用这个路径也可以:E:/Typora笔记/JavaSE/IO流/语录.txt
             stream = new FileInputStream("E:\\Typora笔记\\JavaSE\\IO流\\语录.txt");

             //开始读
            //这个方法的返回值是:读取到的“字节”本身
            int readData = stream.read();
            System.out.println(readData);//229
            
            //再读
            readData = stream.read();
                System.out.println(readData);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //在finally语句块当中确保流一定关闭
            if (stream!=null) { //避免空指针异常
                //关闭流的前提是:流不是空,流是null的时候没必要关闭
                try {
                    stream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

运行结果:

229
189

注意:当再读时,会读取下一个字节

当读取的数值为 -1 时,文本字节读取完毕

FileInputStream循环读

在创建文件字节输入流对象的try 语句块中,添加循环

//            while (true){
//                int readData = fis.read();
//                if (readData==-1){
//                    break;
//                }
//                System.out.println(readData);
//            }

            //改良while循环
            int readDate = 0 ;
            while ((readDate = fis.read()) != -1) {
                System.out.println(readDate);

运行结果(部分):

229
189
147

分析这个程序的缺点:

一次读取一个字节byte,这样内存和硬盘交互太频繁,基本上时间、资源都消耗在交互上面了。

能不能一次读取多个字节呢?可以

IDEA默认当前路径

//相对路径的话呢?相对路径一定是从当前所在位置作为起点开始找!
//IDEA默认的当前路径是哪里?工程Project的根就是IDEA的默认当前路径
// fis = new FileInputStream("temp.txt");
 fis = new FileInputStream("基础语法/src/com/IO/IO流");

往byte数组中读

在创建文件字节输入流对象的try 语句块中,添加byte数组

//开始读,采用byte数组,一次读取多个字节,最多读取 “数组.length” 个字节
byte[] bytes = new byte[4];
//这个方法的返回值是:读取到的字节数量(不是字节本身)
int readCount = fis.read(bytes);
System.out.println(readCount);
//将字节数组全部转换成字符串
//System.out.println(new String(bytes));
//不应该全部都转换,应该是读取了多少个字符,转换多少个
System.out.println(new String(bytes,0 ,readCount));

//虽然读取了四个字节,但是会把第一次读取的四个字节进行覆盖
readCount = fis.read(bytes);
System.out.println(readCount);
System.out.println(new String(bytes));

//读取几个字节就返回几 ,读取不到任何字节返回-1

最终版FileInputStream流

public class FileInputStream04 {
    public static void main(String[] args) {

        FileInputStream fils = null ;

        try {
            fils = new FileInputStream("E:/Typora笔记/JavaSE/IO流/语录.txt");
            //准备一个byte数组
           byte[] bytes= new byte[4];

//            while (true) {
//                int readCount = fils.read(bytes);
//                if (readCount==-1) {
//                    break;
//                }
//                //把byte数组转换成字符串,读到多少个转换多少个
//                System.out.print(new String(bytes,0,readCount));

                int readCount = 0 ;
                while ((readCount = fils.read(bytes)) != -1) {
                    System.out.print(new String(bytes,0,readCount));
                }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fils!=null){
                try {
                    fils.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

运行结果:

Do you love life ? Then do not squander time ; for that's the stuff life is made of .

如果是文件中的内容为中文,可以改变数组长度【乱码的原因是,中文字节只读取了一半】或改变编码为UTF-8

FilleInputStream类的其他方法

1.int available() ; 返回流当中剩余的没有读到的字节数量

try{
fils = new FileInputStream("E:/Typora笔记/JavaSE/IO流/语录2.0.txt");
System.out.println("总字节数量:"+fils.available());
//读1个字节
int readByte = fils.read();
//剩下字节:84
System.out.print("还剩下几个字节未读:"+fils.available());
    }

运行结果:

总字节数量:85
还剩下几个字节未读:84

1.1这个方法有什么所有呢

不需要循环了 , 直接读一次就行了

byte[] bytes = new byte[fils.available()];
这种方式不适合太大的文件,因为byte数组不能太大
int readCount = fils.read(bytes);//85
System.out.println(new String(bytes,0,readCount));

运行结果:

Do you love life ? Then do not squander time ; for that's the stuff life is made of .

注意!:这种方式不适合太大的文件,因为byte数组不能太大

2.long skip(long n) ; 跳过几个字节不读

try {
     fils = new FileInputStream("E:/Typora笔记/JavaSE/IO流/语录2.0.txt");
	 fils.skip(3);
	 System.out.println(fils.read());//121
	 }
	 ...

运行结果:

121

这里输出的是字节

FileOutputStream流

创建文件字节输出流对象:

FileOutputStream fos = new FileOutputStream("文件路径")

代码示例:

FileOutputStream fos = null ;
try {
       //这种方式谨慎使用,这种方式会先将原文件清空,然后重新写入
       fos=new FileOutputStream("E:/Typora笔记/JavaSE/IO流/语录2.0.txt");
       //开始写
       byte[] bytes ={98,99,100,101,102};
       //将byte数组全部写出
       fos.write(bytes);
       //将byte数组的一部分写出!
        fos.write(bytes,0,2);
            
        //写完之后一定要刷新
        fos.flush();
        }

当文件路径所指的文件不存在时,会新建

上述写入会先将原文件清空,然后重新写入,那如何解决呢?在文件尾添加想要的内容?

在文件路径后,添加true即可解决

fos=new FileOutputStream("E:/Typora笔记/JavaSE/IO流/语录2.0.txt",true);

回顾:

将字符串转换为byte数组

String s = "采三秀兮于山间,石磊磊兮葛蔓蔓";
//将字符串转换为byte数组
byte[] bs = s.getBytes();

字节流文件的复制

  • 使用FileInputStream + FileOutputStream完成文件的拷贝
  • 拷贝的过程应该是一边读,一边写
  • 使用以上的字节流拷贝文件的时候,文件类型随意,万能的,什么样的文件都能拷贝
public class Copy01 {
    public static void main(String[] args) {
        FileInputStream fis = null ;
        FileOutputStream fos = null ;

        try {
            //创建一个输入流对象
            fis = new FileInputStream("E:\\Typora笔记\\JavaSE\\集合\\图\\Collection体系集合.png");
            //创建一个输出流对象
            fos = new FileOutputStream("E:/Typora笔记/JavaSE/Collection体系集合.png",true);

            //最核心问题:一边读,一边写
            byte[] bytes = new byte[1024*1024];//一次最多拷贝1m
            int readCount = 0 ;
            if ((readCount=fis.read(bytes))!=-1) {
              fos.write(bytes,0,readCount);
            }

            //刷新
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //分开try,不要一起try,不然第一个异常,第二个就关闭不了了
            //一起try的时候,其中一个出现异常,可能会影响另一个流的关闭
            if (fis!=null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos!=null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

FileReader流

操作基本与FileInputStream相同

但FileReader流使用的不是 byte[] 数组,而是使用 char[] 数组

  • FileReader:
  • 文件字符输入流,只能读取普通文本
  • 读取文本内容时,比较方便,快捷

代码示例

public static void main(String[] args) {
        FileReader reader = null ;
        try {
            reader = new FileReader("E:/Typora笔记/JavaSE/IO流/语录2.0.txt");

            char[] chars = new char[4];//一次读取4个字符
            int readerCount = 0 ;
            while((readerCount = reader.read(chars))!=-1){
                System.out.print(new String(chars,0,readerCount));
            }

运行结果:

采三秀兮于山间,石磊磊兮葛蔓蔓------屈原-《九歌·山鬼》

对字符数组进行遍历

public static void main(String[] args) {
        FileReader reader = null ;
        try {
            reader = new FileReader("E:/Typora笔记/JavaSE/IO流/语录2.0.txt");

           //准备一个char数组
            char[] chars = new char[4];
            //往char数组中读
            reader.read(chars);
            for (char c : chars) {
                System.out.println(c);
            }
            }

运行结果:

采
三
秀
兮

FileWriter流

  • FileWriter:
  • 文件字符输出流,写
  • 只能输出普通文本

代码示例:

public class FileWriterTest {
    public static void main(String[] args) {
        FileWriter writer = null ;
        try {
            writer = new FileWriter("E:/Typora笔记/JavaSE/IO流/语录2.0.txt");
            //如果不想进行覆盖,而是后加
//            writer = new FileWriter("E:/Typora笔记/JavaSE/IO流/语录2.0.txt",true);

            char[] chars = {'我','是','中','国','人'};
            writer.write(chars);//我是中国人
            writer.write(chars,2,3);

            writer.write("我是一名java软件工程师!");
            writer.write("\n");
            writer.write("Hello world!");


            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if (writer!=null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

运行结果(txt文本内):

我是中国人中国人我是一名java软件工程师!
Hello world!

如果不想进行覆盖,而是后加,则在路径后面加 true

writer = new FileWriter(“E:/Typora笔记/JavaSE/IO流/语录2.0.txt”,true);

注意:只能读普通文本文件,其他的都不能读(包括word文本)

字符流文件复制

使用FileReader、FileWriter进行拷贝的话,只能拷贝“普通文本”文件

public class Copy {
    public static void main(String[] args) {
        FileReader reader = null ;
        FileWriter writer = null ;

        try {
            //读
            reader = new FileReader("E:/Typora笔记/JavaSE/IO流/语录2.0.txt");
            //写
            writer = new FileWriter("E:/Typora笔记/JavaSE/IO流/语录3.0.txt");

            //一边读一边写:
            char[] chars = new char[1024*512];//1M
            int readerCount = 0;
            while ((readerCount = reader.read(chars)) != -1) {
                writer.write(chars,0,readerCount);
            }

            writer.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (reader!=null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (writer!=null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 能用记事本编辑的都是普通文本文件
  • 普通文本文件和后缀无关,不一定都是 .txt【.java也是普通文本文件】