Java中的File与字符流,字节流

File

File类概述和构造方法

File:他是文件和目录路径名的抽象表示

  • 文件和目录是可以通过File封装成对象的
  • 对于FIle而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。它可以是存在的,也可以是不存在的,将来是要通过具体的操作吧这个路径的内容转换为具体存在的。

构造方法:

  • FIle( String pathname ):通过将给定的路径名字符串转换为抽象路径名来创建新的File实例
  • File( String parent , String child ):从父路径名字符串和子路径名字符串创建新的File实例
  • File( File parent , String child ): 从父抽象路径名和子路径名字符串创建新的File实例
public static void main(String[] args) {
        File f1 = new File("G:/new.txt");
        System.out.println(f1);     // G:\new.txt
        File f2 = new File("G:/", "new.txt");
        System.out.println(f2);     // G:\new.txt
        File f3 = new File("G:/");
        File f4 = new File(f3, "new.txt");
        System.out.println(f4);     // G:\new.txt
    }

File类创建功能

  • public boolean createNewFile():当具有该名称的文件部存在时,创建一个由该抽象路径名命名的新空文件
  • public boolean mkdir():创建由此抽象路径名命名的目录
  • public boolean mkdirs():创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录

注意:文件的创建方法,在创建位置不包含需要创建的文件/目录时,会返回true,如果需要创建的文件/目录已经存在,那么会返回false。判断文件/目录是否存在是根据方法来的,如果使用创建目录的方法来创建一个后缀为 .txt 的文件,那么会创建文件夹成功,文件夹的名字为 filename.txt。同一级目录下不能同名存在,即使一个为文件,一个为文件夹,也是不允许的。

/*
在G盘下创建一个test目录
在test目录下创建一个test.txt文件
在test目录下创建一个JavaSE目录
在test目录下创建一个JavaWeb/JavaScript多级目录
*/
public static void main(String[] args) throws IOException {
        File f1 = new File("G:\\test");		
        System.out.println(f1.mkdir());		// true
        File f2 = new File("G:\\test\\test.txt");
        System.out.println(f2.createNewFile());		// true
        File f3 = new File("G:\\test\\JavaSE");
        System.out.println(f3.mkdir());		// true
        File f4 = new File("G:\\test\\JavaWeb\\JavaScript");
        System.out.println(f4.mkdirs());		// true
    }

File类判断和获取功能

  • public boolean isDirectory():测试此抽象路径名表示的File是否为目录
  • public boolean isFile():测试此抽象路径名表示的File是否为文件
  • public boolean exists():测试此抽象路径名表示的File是否存在
  • public String getAbsolutePath():返回此抽象路径名的绝对路径字符串
  • public String getPath():将此抽象路径名转换为路径字符串
  • public String getName():返回由此抽象路径名表示的文件或目录的名称
  • public String[] list():返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
  • public File[] listFiles():返回此抽象路径名表示的目录中的文件和目录的File对象数组
public static void main(String[] args) throws IOException {
        File f1 = new File("G:\\test\\test.txt");
        System.out.println(f1.isDirectory());	// false
        System.out.println(f1.isFile());	// true
        System.out.println(f1.exists());	// true
        System.out.println(f1.getAbsolutePath());	// G:\test\test.txt
        System.out.println(f1.getPath());	// G:\test\test.txt
        System.out.println(f1.getName());	// test.txt
        System.out.println("========================");
        File f2 = new File("G:\\test");
        String[] list = f2.list();
        File[] files = f2.listFiles();
        for (String s: list) {
            System.out.print(s + "\t");		// JavaSE	JavaWeb	test.txt
        }
        System.out.println();
        for (File file: files) {
            System.out.print(file + "\t");		// G:\test\JavaSE	G:\test\JavaWeb	G:\test\test.txt
        }
    }

File类删除功能

  • public boolean delete():删除由此抽象路径名表示的文件或目录

绝对路径:完整的路径名,不需要任何其他信息就可以定位它所表示的文件,例如:G:/JavaWeb/JavaScript

相对路径:必须使用取自其他路径名的信息进行解释,如:Java/java.txt

**如果一个目录中有内容(文件,目录),那么不能直接删除这个目录,需要将目录下的所有内容删除,才能删除该目录。

递归遍历文件夹下所有内容

要求:遍历指定位置下的所有内容,如果是多级文件,则要把每一层的所有内容都遍历输出

思路:用指定路径创建一个file对象,使用listFiles()方法获取此目录下的所有内容,遍历这个数组,如果为文件夹,则深入遍历,并且输出文件夹名称,如果为文件,则直接输出文件名称

public static void main(String[] args) throws IOException {
        File f1 = new File("G:\\test");	// 用G:/test创建对象
        File[] files = f1.listFiles();	// 遍历内容,形成数组
        if(files != null) {	// 不为空则开始遍历
            for (File file : files) {	// 调用打印方法
                printFile(file);
            }
        }
    }
    public static void printFile(File file){	// 这是一个递归方法
        if(file.isDirectory()){	// 判断是否为文件夹
            System.out.println("这是一个文件夹:" + file.getName());
            File[] listFiles = file.listFiles();	// 遍历此文件夹下的所有内容
            for (File listfiles: listFiles) {	 
                printFile(listfiles);	// 实现递归调用
            }
        }else{	// 这是一个文件
            System.out.println("这是一个文件:" + file.getName());
        }
    }
/* 
这是一个文件夹:JavaSE
这是一个文件:JavaEE.txt
这是一个文件夹:JavaWeb
这是一个文件夹:JavaScript
这是一个文件:PHP.txt
这是一个文件:test.txt
*/
/*
实际的目录结构如下:
G:/test		为指定目录,接下来为他的所有内容
JavaSE ———— JavaEE.txt	(表示JavaEE.txt 在 JavaSE 文件夹下,JavaSE 在test下)
JavaWeb ———— JavaScript ———— PHP.txt
test.txt
*/

字节流

IO流概述和分类

  • IO :输入/输出(Input/Output)
  • 流:是一种抽象概念,是对数据传输的总称,也就是收数据在设备间的传输称为流,流的本质是数据传输
  • IO流就是用来处理设备间数据传输问题的,常见的应用:文件复制,文件上传,文件下载

分类:

  • 按照数据的流向

    • 输入流:读数据
    • 输出流:写数据
  • 按照数据类型

    • 字节流
      • 字节输入流
      • 字节输出流
    • 字符流
      • 字符输入流
      • 字符输出流

如果文件通过记事本打开,我们能够读懂其中的内容,那么就使用字符流读写数据,如果我们读不懂,则使用字节流读取。无法选择使用那种方式读取的时候,使用字节流。

字节流写数据

字节流抽象基类

  • InputStream:这个抽象类使表示字节输入流的所有类的超类
  • OutputStream:这个抽象类是表示字节输出流的所有类的超类
  • 子类名特点:子类名称都以其父类名作为子类名的后缀。****InputStream

使用字节输出流写数据的步骤:

  • 创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出对象指向文件),如果文件已经存在,则不会创建
  • 调用字节输出流对象的写数据方法
  • 释放资源(关闭文件,释放系统资源),所有IO流操作最后都要释放资源
public static void main(String[] args) throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream("G:\\test.txt");
        fileOutputStream.write(86);	// 这里的86是ASCII码,对应的内容是V
        fileOutputStream.close();
    }

字节流写数据的三种方式

  • void write( int b ):将指定的字节写入此文件输出流,一次写入一个数据
  • void write( byte[] b ):将 b 数组写入此文件中,一次写一个字节数组数据
  • void write( byte[] b, int off, int len ):将len字节从指定字节数组开始,从偏移量off开始写入此文件输出流,一次写入一个字节数组的部分数据。总共写入len个数据。(如:bys为(A,B,C,D,E),那么 write(bys,1,3) 则会写入 BCD 三个数据, write(bys,2,3) 则会写入 CDE 三个数据)

在写入一串字符串时,如果要自行查ASCII码,会变得非常麻烦,可以使用String的getBytes()方法

String.getBytes():返回字符串所对应的字节数组

byte[] bys = "hello world!".getBytes();
fos.write(bys);

字节流写数据中的换行与追加写入

不同的操作系统所识别的换行符是不一样的。

  • windows:\r\n
  • Linux:\n
  • mac:\r
// 换行
for (int i = 50; i < 60; i++) {
            fileOutputStream.write(i);
            fileOutputStream.write("\n".getBytes());
        }
// 追加写入
// public FileOutputStream ( String name, boolean append )
// 创建文件输出流以指定的名称写入文件
// 如果第二个参数为true,则字节将写入文件的末尾而不是开头
FileOutputStream fileOutputStream = new FileOutputStream("G:\\test.txt" , true );

字节流写数据的异常处理

使用 try catch 语句块将IO操作抓取异常,如果出现异常,结束进程并且释放资源,所以应该使用finally来释放资源

FileOutputStream fos = null;
try{
    // IO操作
}catch (IOException e){
    e.prtinStackTrace();
}finally{
    fos.close
}

而在实际应用中,我们还需要考虑更多,如下

public static void main(String[] args) throws IOException {
        FileOutputStream fos = null;    // 由于finally要关闭资源,使用fos,所以定义在try catch外面,初始值给null,否则会报空指针异常
        try{
            fos = new FileOutputStream("X:\\test");     // 没有X盘,创建失败,fos为空
            fos.write(97);
        }catch (IOException e){
            e.printStackTrace();
        }finally{
            if(fos != null){    // 如果直接使用fos.close,如果在创建文件时失败,那么fos就为空,此时使用fos.close会出现空指针异常
                try {   // 这个try catch 是因为初始化fos的时候给了 null ,所以存在IO异常
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

字节流读数据

一次性读一个字节数据

public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("G:\\test.txt");
        int by;
        // -1 表示已经到了文件末尾
        while((by = fis.read()) != -1){     // 把fis.read()赋值给by,然后判断是否为-1,
            System.out.print((char)by);	// 使用print输出,是因为它能读取到文件中的换行,会自动换行,输出格式与记事本中格式一致
        }
    }

一次读一个字节数组数据

public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("G:\\新建文本文档.txt");
        byte[] bys = new byte[1024];	// 长度一般为1024或者1024的整数倍
        int len;	// len是实际读取到数据的个数
        while((len = fis.read(bys)) != -1){		// 如果为 -1 表示到文件末尾
            System.out.print(new String(bys,0,len));	// 从 0 读取到 len
        }
        fis.close();
    }

System.out.print(new String(bys,0,len)); 这一句话非常重要,要设置输出为 0 到 len,这样才会读取多少数据则输出多少数据,不会输出过多的数据。

String( byte[] , offset , int length) 把字节数组的一部分转成字符串

字节流复制文本文件

public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("G:\\test.txt");
        FileOutputStream fos = new FileOutputStream("D:\\test.txt");
        int by;
        while((by = fis.read()) != -1){
            fos.write((char)by);
        }
        fis.close();
        fos.close();
    }

字节流复制图片

public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("G:\\图片\\风景素材\\hai.jpg");
        FileOutputStream fos = new FileOutputStream("D:\\hai.jpg");
        byte[] bys = new byte[1024];
        int len;
        while((len = fis.read(bys)) != -1){
            fos.write(bys,0,len);
        }
        fis.close();
        fos.close();
    }

字节缓冲流

  • BufferOutputStream:该类实现缓冲输出流,通过设置这样的输出流,应用程式可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
  • BufferedInputStream:创建BufferedInputStream将创建一个内部缓冲区数组,当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节

构造方法

  • 字节缓冲输出流:BufferedOutputStream( OutputStream out )
  • 字节缓冲输入流:BufferedIutputStream( IutputStream in )

为什么构造方法需要的是字节流,而不是具体的文件或者是路径呢?

  • 字节缓冲流仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作
public static void main(String[] args) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("G:\\新建文本文档.txt"));
        byte[] bys = new byte[1024];
        int len;
        while((len = bis.read(bys)) != -1){
            System.out.print(new String(bys,0,len));
        }
        bis.close();
    /*
    	BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("G:\\test.txt"));
        bos.write("hello world!".getBytes());
        bos.close();*/
    }

字节流复制视频

public static void main(String[] args) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("G:\\心灵的声音\\01 - 出击.flv"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("G:\\01 - 出击.flv"));
        byte[] bys = new byte[102400];
        int len;
        while((len = bis.read(bys)) != -1){
            bos.write(bys,0,len);
        }
        bis.close();
        bos.close();
    }

使用字节缓冲流,效率比其他方式要高

字符流

为什么会出现字符流

一个汉字存储,如果是GBK编码,占用2个字节,如果是UTF-8编码,占用3个字节。不管使用哪种编码,汉字的第一个字节一定是负数,所以使用字节流读写,复制文件时,中文也不会出错

public static void main(String[] args) throws IOException {
        String s = "中国";
        byte[] bys = s.getBytes("UTF-8");
        byte[] bys2 = s.getBytes("GBK");
        System.out.println(Arrays.toString(bys));	// [-28, -72, -83, -27, -101, -67]
        System.out.println(Arrays.toString(bys2));	// [-42, -48, -71, -6]
    }

字符流 = 字节流 + 编码表,方便操作中文

编码表

字符集

  • 是一个系统支持的所有字符的集合,包括各国家的文字、数字、标点符号、图形符号等
  • 计算机需要准确的存储和识别各种字符集型号,就需要进行字符编码,一套字符集至少有一套字符编码

GBK:最常用的中文码表,是在GB2312(简体中文码表)标准基础上的扩展规范

Unicode字符集:

  • 为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码,标准万国码。有三种编码方案:UTF-8 , UTF-16 ,UTF-32,其中最为常用的为UTF-8。

UTF-8:它使用一至四个字节为每个字符编码,编码规则:

  • 128个US-ASCII字符,只需要一o个字节编码
  • 拉丁文等字符,需要两个字节编码
  • 大部分常用字(包含中文),使用三个字节编码
  • 其他极少使用的Unicode辅助字符,使用四字节编码

对应的编码规则要使用相应的解码规则进行解码,否则会乱码。

字符串中的编码解码问题

编码

  • byte[] getBytes():使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中
  • byte[] getBytes( String charsetName ):使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中

解码

  • String( byte[] bytes ):使用平台的默认字符集解码指定的字节数组来构造新的String
  • String( byte[] bytes , String charsetName ):通过指定的字符集解码指定的字节数组来构造新的String
public static void main(String[] args) throws IOException {
        String s = "中国";
        byte[] bys = s.getBytes("UTF-8");
        byte[] bys2 = s.getBytes("GBK");
        String gbk = new String(bys, "GBK");	// 不对应解码
        System.out.println(gbk);	// 涓浗

    }

字符流中的编码解码问题

字符流抽象基类

  • Reader:字符输入流的抽象类
  • Writer:字符输出流的抽象类

字符流中和编码解码问题相关的两个类

  • InputStreamReader:使用指定的charset读取字节并将其解码为字符
  • OutputStreamWriter:使用指定的charset将写入的字符编码为字节

构造方法:

编码

  • OutputStreamWriter( OutputStream out ):使用默认字符集

  • OutputStreamWriter( OutputStream out , String charsetName):使用指定字符集

解码

  • InputStreamReader( InputStream in ):创建一个使用默认字符集的InputStreamReader

  • InputStreamReader( InputStream in , String charsetName ):创建使用指定字符集

public static void main(String[] args) throws IOException {
        InputStreamReader isr = new InputStreamReader(new FileInputStream("G:\\test\\test.txt"), "GBK");
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("G:\\test\\test.txt"), "GBK");
        osw.write("这是一串中文");
        osw.close();	// 注意这个关闭的位置
        int ch;
        while((ch = isr.read()) != -1){
            System.out.print((char)ch);
        }
        isr.close();
    }

如果使用字符流编码解码读取数据,那么输出流必须在读取数据操作之前关闭,否则不会在控制台输出数据

字符流写数据的五种方式

  • void write( int c ):写入一个字符
  • void write( char cbuf[ ] ):写入一个字符数组
  • void write( char[ ] cbuf, int off, int len ):写入字符数组的一部分
  • void write( String str ):写入一个字符串
  • void write( String str, int off, int len ):写入一个字符串的一部分

void flush():刷新流

void close():方法会在关闭流之前先进行刷新

流一旦被关闭,就不能再调用进行读取或写入数据

字符流读数据的两种方式

  • int read():一次读一个字符数据
  • int read( char[] cbuf ):一次读一个字符数组数据

字节流读数据与字符流读数据格式是一样的,只不过前者是读字节,后者是读字符

字符流的便捷类

当我们不用指定编码,只使用默认编码时,可以使用转换流的子类进行操作

  • FileReader:用于读取字符文件的便捷类

    ​ FileReader( String fileName )

  • FileWriter:用于写入字符文件的便捷类

    ​ FileWriter( String fileName )

public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("G:\\test\\test.txt");
    	// 相当于如下语句
    	// InputStreamReader isr = new InputStreamReader(new FileInputStream("G:\test\test.txt"));
        FileWriter fw = new FileWriter("G:\\test.txt");
    	// OutputStreamWriter ows = new OutputStreamWriter(new FileOutputStream("G:\\test.txt"));
        char[] chr = new char[1024];
        int len;
        while((len = fr.read(chr)) != -1){
            fw.write(chr,0,len);
        }
        fr.close();
        fw.close();
    }

字符缓冲流

  • BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可指定缓冲区大小,一般使用默认大小( 8192 )
  • BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可指定缓冲区大小,一般使用默认大小。

构造方法

  • BufferedWriter( Writer out )
  • BufferedReader( Reader in )
public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("G:\\test\\test.txt"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("G:\\test.txt"));
        char[] chr = new char[1024];
        int len;
        while((len = br.read(chr)) != -1){
            bw.write(chr,0,len);
        }
        br.close();
        bw.close();
    }

字符缓冲流的特有功能

BufferedWriter

  • void newLine():写一行行分隔符,行分隔符字符串由系统属性定义( Linux : \n Mac : \r)

BufferedReader

  • public String readLine():读一行文字,结果包含行的内容的字符串,不包括任何终止字符,如果流的结尾已经到达,则为null
BufferedWriter bw = new BufferedWriter(new FileWriter("G:\\test.txt"));
for(int i = 0 ; i < 10 ; i++ ){
    bw.write("hello" + i);	// 写数据的三个步骤
    bw.newLine();
    bw.flush();
}
bw.close();

BufferedReader br = new BufferedReader(new FileReader("G:\\test\\test.txt"));
String line;
while((line = br.readLine()) != null){
    System.out.println(line);	// 注意此处使用了println,是因为readLine()不会读取换行符,需要手动换行
}
br.close();

使用 readLine() 写数据三步骤:①.写入数据 ②.写入换行符 ③.刷新流

最常用的字符流复制文件方法

如果复制照片以及视频文件,会存在无法正常开启的现象

public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("G:\\test\\test.txt"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("G:\\test.txt"));
        String line;
        while((line = br.readLine()) != null){
            bw.write(line);
            bw.newLine();
            bw.flush();
        }
        br.close();
        bw.close();
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值