[java基础复习] IO和File

File class

在Java中,class File是java用来处理文件的对象。它的使用一般是

File file = new File("e://");
// File e = new File("absolutePath");

//获取file1的父路径,在该路径下创建一个名为newFile的文件夹
File f = new File(file1.getParentFile(), "newFile");
//File f = new File(String parent, String child);
//意思是在parent这个路径下,创建一个名为child的文件或者文件夹

文件File类可以不关闭,但是IO一定要关闭!!!

如果指定的路径是具体文件的名字,比如new File(“e://a.txt”) 那么就只会打开一个文件。如果设定的是一个路径,那么file会一次性全部读取路径下的所有文件,可以使用 .listFiles() 然后遍历。贴一段代码,代码目的是输出所有文件结尾是avi且文件大小大于100MB的

public class Demo4 {
    public static void main(String[] args) {
        File e = new File("e://");
        File[] files = e.listFiles();
        //调用自己写的listFile来操作
        listFile(files);
    }

    public static void listFile(File[] files){
    	//这个一定要加,防止文件操作空指针
        if(files!=null&&files.length>0){
        	//foreach循环File[]数组
            for (File file:files) {
            	//如果是文件,进行.avi判定
                if(file.isFile()){
                    if(file.getName().endsWith(".avi")){
                    	//要求文件大小大于100MB
                        if(file.length()>100*1024*1024)
                        System.out.println("找到了一个avi文件"+file.getAbsolutePath());
                    }
                //如果是文件夹则进行文件夹内部循环。
                //文件夹判定为file.isDirectory();
                }else {
                    File[] files2 = file.listFiles();
                    listFile(files2);
                }
            }
        }
    }
}

IO

1. IO 概述

 可以将这种数据传输操作,看做一种数据的流动 , 按照流动的方向分为输入Input和输出Output
 Java中的IO操作主要指的是 java.io包下的一些常用类的使用. 通过这些常用类对数据进行读取(输入Input) 和 写出(输出Output)
 
 IO流的分类:
 按照流的方向来分,可以分为:输入流和输出流.
 按照流动的数据类型来分,可以分为:字节流和字符流
 
 字节流:(操作中文会乱码)
           -   输入流 :   InputStream
           -   输出流 :   OutputStream
 字符流:
           -   输入流 :   Reader
           -   输出流 :   Writer
           
 1字符 = 2字节
 1字节 = 1byte = 8bit
 
 一切皆字节:
 计算机中的任何数据(文本,图片,视频,音乐等等)都是以二进制的形式存储的.
 在数据传输时 也都是以二进制的形式存储的.
 后续学习的任何流 , 在传输时底层都是二进制.
  
 流操作完必须关闭!!!!!!!!!!!

2. 字节流操作

字节流用的比较多,因为它可以操作任何文件。但是字符流对于操作String会比较好用,因为它自带方法,且按照字符读取

2.1 OutputStream

这是个抽象类,常见用法如下:
在这里插入图片描述

2.1 常用子类 FileOutputStream

这是OutputStream最常见的子类,调用结束一定要执行close()

// 这里要注意!你的方法一定要throws IOException, 
// 因为有的时候创建是会失败的,这个下面说。

// 1. 使用字符串指定文件名称
//FileOutputStream fos = new FileOutputStream(String name);
FileOutputStream fos = new FileOutputStream("c://a.txt");

// 2. 使用字符串指定文件名称,并且写入采用的是追加方式
//FileOutputStream fos = new FileOutputStream(String name, boolean flag);
FileOutputStream fos = new FileOutputStream("c://a.txt", true);

// 3. 创建输出流,并指定将要输出到的文件
//FileOutputStream fos = new FileOutputStream(File file);
FileOutputStream fos = new FileOutputStream(file);

// 3. 创建输出流,并指定将要输出到的文件。写入方式为追加模式。
//FileOutputStream fos = new FileOutputStream(File file, boolean flag);
FileOutputStream fos = new FileOutputStream(file, true);

接下来写一个例子,这个例子里有如何输入,输入格式以及效果
注意在下面的main方法后面加了throws IOException!

public class OutputStreamDemo {
    //OutputStream
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("c://a.txt");
        fos.write(65); //这里写入文本的是A
        byte[] bytes = "123".getBytes(); //这里写入文本的是123
        fos.write(bytes);
    }
}

fos.write()括号内只能输入int/ byte[]/ (byte[], int start, int len)
第三个是只从bytes数组中的start下标开始读,读len个。
注意这里的输出第一个是A,第二个是123。因为这里输入的int是按照ASCII转换的字符,所以会变成A。原因是fos只向下取低8位。(int是4字节,低八位就是最末尾的1字节,8bit,最大255,对应ASCII的255位编码,所以是64)
如果想输入固定字符,让他保持不变的话就用byte[] bytes = string.getBytes(); 这样可以保证输入。

2.2 InputStream
常用子类FileInputStream

这个和上面同理,调用结束一定要执行close()。
通常我们写的下载就是用这个,从文件中读数据。我们一般的做法都是设置一个大小的byte数组,然后每次循环读,直到读完。
这里注意一下,调用fis.read(byte[]) 这里返回的是真实读取到的byte长度,并把它赋值到bytes这个数组里。
请注意看代码里len的注释!!!

public class FISDemo {
    //InputStream
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("c://a.txt");
        byte[] bytes = new byte[10];
        int len = 0;
        while(len > -1){
        	//这里为什么要判断len呢?
        	//首先len = -1说明文件已经读到结尾了,毋庸置疑
        	//其次判断len的最关键的问题就是,文件的大小很可能不是你设置的bytes数组的长度的n倍
        	//举个例子,有26个字母,那么第三次读取的时候其实只有6个
        	//也就是说这6个会覆盖bytes的前6个元素,但是第二次读取的后四个
        	//并不受影响。因此!最后一次会多出4个!
        	//但是如果每次读取判定len,用new String(bytes,0,len)去读,就不会读到重复的后四位了,嘿嘿
	        len = fis.read(bytes);
	        System.out.println(new String(bytes,0,len));
        }
        fis.close();
    }
}
注意点

字节流操作有一个很大的问题,就是遇到中文的时候。因为他是一个一个字节操作,但是对于中文来说,一个汉字三个字节,因此有的时候会读一半半。可以解决的方法是读取的长度一定大于中文的长度,但是这个往往在真实设计中难以实现。
下面举个例子,输入是“锄禾日当午”,byte[]长度是10。它读前三个用了9byte,最后一个只有1byte了,就会输出乱码。
在这里插入图片描述

3. 字符流

与字节流的区别是,一次性读的是一整个字符,所以比较适合字符操作。从原理上来说,毕竟万物皆字节,字符流只不过是有一个内置的缓存,一个一个读取字节,直到形成了一个字符才输出。所以字符流操作单位是char,而不是byte,进行操作的数组也是char[],而不是byte[]

3.1 Writer
常用子类 FileWriter

使用方法基本与OutputStream一致,但是多了一个append的方法。

首先说明这个方法并不是默认文件写入格式为追加模式,就是在申明FileWriter fw的时候如果后面不是true,那么一样会直接覆盖而不是追加!
其次,这个方法的操作返回的是一个this,属于Writer类。

什么意思呢,就是说我用fw.append(“abc")之后会返回一个fw,它是添加完abc内容的。所以如果你用FileWriter fw2 = fw.append(“锄禾日当午”),那么fw2 == fw会返回true。因为在内存里指向的是同一个地址。

public class FileWriterDemo {
    public static void main(String[] args) throws IOException {
        //writer
        FileWriter fw = new FileWriter("c://b.txt",true);
        //在文件fw中不停的追加
        fw.append("锄禾日当午").append(",").append("汗滴禾下土");   //可以一致追加
        fw.write("锄禾日当午");
        fw.flush();        //刷新
        fw.close();

    }
}
Reader
常用子类 FileReader

reader的注意点也和InputStream一样,首先判断是否读到文件结尾,用fr.read()方法返回的int来确定,-1即文件结尾。
这里注意一下,如果是fr.read(),那么代表我每次只读一个字符,所以返回的是字符在ASCII里转换成数字的值。
如果是fr.read(byte[] bytes),那么意思是我将读到的内容尽可能填满byte数组。那么返回的是改次读取的长度。
注意下面读取的数组是char[],而不是byte[]

public class Demo10 {
    public static void main(String[] args) throws IOException {
        //reader
        FileReader fr = new FileReader("b.txt");
        char[] chars = new char[100];
        while (true){
            int c = fr.read(chars);
            if(c==-1){
                break;
            }
            System.out.println(new String(chars, 0, len));
        }        
        fr.close();
    }
}
4. flush()

这里提一嘴flush,一个重要的方法和概念。这个方法是强制刷新缓存区,将缓存区的内容写入文件中。其实在字符流和字节流中都存在缓存区,如果缓存区溢出那么就会直接将缓存区内容写入到文件中。而字节流的缓存区非常小,所以一般的输入都会导致溢出,就自动写入了。但是字符流的缓存区就比较大,如果不写满就无法写入到文件中。这时候就可以调用flush(),强制将缓存区内容写入文件。人为写flush()是个好习惯!并且flush()还有个好处是它可以控制实时通讯。同时close()方法会自动实现flush,所以如果文件较小可以直接close。

4. 字节流转换为字符流

给个简单的例子
基本上使用InputStreamReader读取字节流文件,还可以定义编码格式。
InputStreamReader isr = new InputStreamReader(字节流, String 编码格式);

public static void main(String[] args) throws IOException {
    //转换流  :将字节流转换成字符流     使用了装饰者模式
    FileInputStream fis = new FileInputStream("c://a.txt");
    //将字节输入流转换为字符输入流  参数为要转换的字节流
    InputStreamReader isr = new InputStreamReader(fis,"gbk");
    while (true){
        int c = isr.read();
        if(c==-1){
            break;
        }
        System.out.println((char) c);
    }
}
BufferedReader

这个类中有一个方法是readLine(),它允许一次性读一整行,不需要像前面定义一个数组或者是一个一个读,就很方便

try-with-resource

JDK 1.7时允许在try中间创建文件,避免后面写太多异常处理的冗余代码

//jdk7
try(FileReader fr = new FileReader("c://book.txt");){
    int c = fr.read();
    System.out.println((char)c);
}catch (IOException e) {
    e.printStackTrace();
}

但是还有一个不好的地方就是,如果这个流是之前创建的,就无法进行关闭或是在try catch之后还想继续使用,也无法调用。

所以JDK 1.9 允许在try catch模块外面创建,并且在try()的括号中写入可能出错的IO流,用分号隔开

//jdk9
FileReader fr = new FileReader("c://book.txt");
PrintWriter pw = new PrintWriter("c://book.txt");
try(fr;pw){
    int c = fr.read();
    System.out.println((char)c);
}catch (IOException e) {
    e.printStackTrace();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值