JavaIO之File类、字节和字符流

一、File操作

在java.io包中,File是唯一一个与文件本身操作(创建、删除、取得信息...)有关的程序类。

1.和File类有关的方法

构造方法:
public File(String pathname);//文件在pathname路径下
public File(String parent,String child),设置父路径和子路径。
其它方法:
public boolean createNewFile() throws IOException;创建一个新文件。
public boolean exists();判断文件是否存在。
public boolean delete();删除文件
package com.xunpu.file;

import java.io.File;
import java.io.IOException;
/**
 *File有关方法的使用
 */
public class Demo1 {
    public static void main(String[] args) {
        //在E:\\DEMO1目录下创建Demo1.txt文件
        File file=new File("E:\\DEMO1\\aaa.txt");
        //如果文件存在,就删除。
        if(file.exists()){
            file.delete();
            System.out.println("文件已存在,删除");
        }else {
            try {
                boolean isSuccess=file.createNewFile();
                if(isSuccess){
                    System.out.println("文件不存在,重新创建文件,创建成功");
                }else{
                    System.out.println("文件不存在,重新创建文件失败!!");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

创建成功

不同操作系统中路径分隔符不同,Linux下是"/",而Windows下是"\",为了解决这个问题,通常使用File类的一个常量public static final String separator来描述。使用为:File.seperator

2.和目录有关的方法

public String getParent();取得父路径
public File getParentFile();取得父File对象
public boolean mkdirs() 创建目录(不论有多少级,都会创建)
package com.xunpu.file;

import java.io.File;

/**
 * 目录有关方法的使用
 */
public class Demo2 {
    public static void main(String[] args) {
        //设置file为Demo1.java文件
        File file=new File("D:"+File.separator+"Java项目"+File.separator+"javaIO"+File.separator+"src"
                +File.separator+"main"+File.separator+"java"+File.separator+"com"+File.separator+"xunpu"+File.separator+
                "file"+File.separator+"Demo1.java");
        System.out.println(file.getParent());//取得父路径
        System.out.println(file.getParentFile());//取得父File对象
        file=new File("E:"+File.separator+"JavaFile"+File.separator+"Directory"+File.separator+"bbb");
        if(!file.exists()) {
            boolean isMkdir = file.mkdirs();
            if (isMkdir) {
                System.out.println("文件夹不存在,现重新创建成功");
            }else{
                System.out.println("文件夹不存在,现重新创建失败");
            }
        }else{
            System.out.println("文件夹已经存在");
        }
    }
}

最终在E盘递归创建文件夹。

3.和文件信息有关的操作

public boolean isFile();判断路径是否是文件
public boolean isDirectory();判断路径是否是目录
public long length();取得文件大小(字节)
public long lastModified();最后一次修改日期
package com.xunpu.file;

import java.io.File;
import java.util.Date;

/**
 * 文件信息的有关方法使用
 */
public class Demo3 {
    public static void main(String[] args) {
        File file=new File("E:"+File.separator+"JavaFile"+File.separator+"Directory"+File.separator+"bbb");
        //判断是否是文件
        if(file.isFile()){
            System.out.println("bbb是文件");
        }
        //判断是否是目录/文件夹
        if(file.isDirectory()){
            System.out.println("bbb是目录或者文件夹");
        }
        System.out.println("文件的大小为:"+file.length()+"字节");//计算的是其内文件夹的大小
        long time=file.lastModified();//获取文件最后一次修改的时间,返回值是long类型。
        //将long类型转换为Date类型
        Date date=new Date(time);
        System.out.println("bbb最后一次修改的时间为:"+date);
    }
}

4.综合案例

需求:给定一个文件夹名,要求打印出该文件夹下所有的子文件的名称,大小和修改时间。

package com.xunpu.file;

import java.io.File;
import java.util.Date;

/**
 * 综合案例:指定文件夹,要求列出文件夹中所有文件夹的大小
 */
public class Demo4 {
    public static void main(String[] args) {
        File file=new File("D:"+File.separator+"Java项目"+File.separator+"javaIO"+File.separator+"" +
                "src"+File.separator+"main"+File.separator+"java"+File.separator+"com"+File.separator
                +"xunpu");
     listAllFileInfo(file);
    }

    private static void listAllFileInfo(File file) {
        if(file==null){
            return;
        }
        if(file.isFile()){
            System.out.print(file);
            System.out.println("  文件大小为:"+file.length()+"字节  文件最后一次的修改日期为:"
                    +new Date(file.lastModified()));
        }else if(file.isDirectory()){
            File[] files=file.listFiles();
            for(File item:files){
                listAllFileInfo(item);
            }
        }
    }
}

现在的代码可能会发生线程阻塞问题,当前的操作是在main线程下进行的。如果listAllFileInfo()没有完成,main后序的操作是无法进行的。这种耗时的操作让主线程出现了阻塞,导致后续代码无法正常执行完毕。此时,不想发生阻塞,最好让lsitAllFileInfo()在另一个线程中完成。

package com.xunpu.file;

import java.io.File;
import java.util.Date;

/**
 * 不产生阻塞,打印出文件的详细信息
 */
public class Demo5 {
    public static void main(String[] args) {
        Thread thread=new Thread(){
            @Override
            public void run(){
                File file=new File("D:"+File.separator+"Java项目"+File.separator+"javaIO"+File.separator+"" +
                        "src"+File.separator+"main"+File.separator+"java"+File.separator+"com"+File.separator
                        +"xunpu");
                listAllFileInfo(file);
            }
        };
        thread.start();

    }
    private static void listAllFileInfo(File file) {
        if(file==null){
            return;
        }
        if(file.isFile()){
            System.out.print(file);
            System.out.println("  文件大小为:"+file.length()+"字节  文件最后一次的修改日期为:"
                    +new Date(file.lastModified()));
        }else if(file.isDirectory()){
            File[] files=file.listFiles();
            for(File item:files){
                listAllFileInfo(item);
            }
        }
    }
}

二、字节流和字符流

File类不支持文件内容处理。如果要处理文件内容,必须通过流的操作模式来完成。

1.流的分类

按输入/输出分为:输入流:InputStream和Reader  输出流:OutputStream和Writer

按字节流/字符流:字节流:InputStream和OutputStream  字符流:Writer和Reader

2.字节流和字符流的区别

本质区别:字节流是原生操作,而字符流是经过处理后的操作。

在进行网络数据传输和磁盘保存数据时,只支持字节的数据类型。

字符更加适合处理中文。

注意:IO操作属于资源处理,所有的资源处理操作(IO操作、数据库操作、网络)最后必须要进行关闭。

三、字节流和文件操作

1.字节流类及其子类

说明:

1)ByteArrayOutputStream/ByteArrayInputStream:把字节数组转换为输出流/输入流

2)FileOutStream/FileInputStream:从文件中写/读取数据。

3)PipedOutputStream/PipedInputStream:连接一个PipedInutStream或PipedOutputStream

4)ObjectOutputStream/ObjectInputStream:对象输出流/对象输入流,常用于序列化中。

5)FilterOutputStream/FilterInputStream:装饰器,扩展其它输出流/输入流的功能。

6)SequenceInputStream:把几个输入流转换为一个输出流。

2.字节流(OutputStream和InputStream)的一些方法

OutputStream:(写数据有关的方法)
void write(int b);//写入一个字节
void write(byte[] b);//把参数b指定的字节数组中的所有字节写到输入流。
void write(byte[] b,int off,int len);//把参数b指定的字节数组中的若干字节写到输出流,参数off指定字节数组开始的起始下标,从这个位置开始输出由参数len指定数目的字节。
void close();//关闭输出流
void flush();//OutputStream本身的flush()不执行任何操作,它的一些带有缓冲区的子类(比如BufferedOutputStream和PrintStream类)覆盖了flush()。通过带缓冲区的输出流写数据时,数据先保存在缓冲区中,积累到一定程度才会真正写到输出流中。缓冲区通常由字节数组实现,实际上指一块内存空间。flush()强制把缓冲区中的数据写到输出流中。
InputStream:(读数据有关的方法)
int read();//读一个字节,并把它转换为0~255之间的整数并返回。
int read(byte[] b);//读若干字节,并保存到参数b指定的字节数组中,返回字节数;如果读到末尾,返回-1.
int read(byte[] b,int off,int len);//读若干字节,从off处开始,指定len个字节,返回实际读取的字节数。
void close();//同OutputStream
int available();//返回可以从输入流读取的字节数
skip(long n);//从输入流中跳过参数n指定的字节数目。
boolean markSupported();//判断流是否支持重复读入数据。返回true,说明可以在流上设置标记。
void mark(int readLimit);//从流的当前位置开始设置标记,readLimit在流上指定标记的字节数。
void reset();//使输入流重新定位到刚才做标记的起始位置。

3.和文件操作有关的方法使用

public FileOutputStream(File file) throws FileNotFoundException;接收File类(覆盖)

public FileOutputStream(File file,boolean append);接收File类(追加)

文件操作的基本步骤:

1)根据文件路径创建File类对象。

2)根据字节流或字符流的子类实例化父类对象。

3)进行数据的读取或写入操作。

4)关闭流(close())

package com.xunpu.myio;

import java.io.*;

/**
 *文件的写入和输出操作
 */
public class Test1 {
    public static void main(String[] args) {
        //1.创建file对象
        File file=new File("E:"+File.separator+"JavaFile"+File.separator+"Directory"+File.separator+"bbb"
        +File.separator+"aaa.txt");
        try {
            //2.创建OuputStream对象(写数据)
            OutputStream outputStream=new FileOutputStream(file);
            //3.执行文件的写操作
            String str="hello world";
            byte[] bytes=str.getBytes();//将字符串转换为字符数组
            outputStream.write(bytes);//写到文件中
            //执行文件的读操作
            //创建InputStream对象(读数据)
            InputStream inputStream=new FileInputStream(file);
            byte[] data=new byte[1024];//定义每次最多可以读1024个字节
            int len=inputStream.read(data);//将读取的数据放入数组中
            String res=new String(data,0,len);//在这里,可以修改len,控制输出的字符数
            System.out.println("文件中的内容为:"+res);
            res=new String(data,0,7);//hello w
            System.out.println(res);
            //4.关闭流
            outputStream.close();
            inputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

4.AutoCloseable自动关闭支持

JDK1.7支持.  目的:自动进行关闭处理。  使用方法:必须结合try...catch使用.

package com.xunpu.myio;

/**
 * AutoCloseable接口的使用:
 * 1.创建一个类继承AutoCloseable接口
 * 2.在try中定义子类
 * 3.在try中执行有关方法
 */
class Message implements AutoCloseable {

    public void close() throws Exception {
        System.out.println("关闭资源");
    }
}
public class Test2 {
    public static void main(String[] args) {
        try(Message message=new Message()) {//在try中定义对象,会自动给关闭。
            message.close();//重复关闭,显示“多余的关闭”
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

InputStream和OutputStream的定义:

public abstract class OutputStream implements Closeable, Flushable;

public abstract class InputStream implements Closeable;

public interface Closeable extends AutoCloseable;

可以看到这两个类都继承了Closeable接口,而Closeable接口又实现了AutoCloseable接口,因此,InputStream和OutputStream也都可以实现自动关闭,这只需要在try中定义即可。

package com.xunpu.myio;

import java.io.*;

/**
 * InputStream和OutputStream的自动关闭
 */
public class TestAutoCloseable {
    public static void main(String[] args) {
        //1.创建file对象
        File file=new File("E:"+File.separator+"JavaFile"+File.separator+"Directory"+File.separator+"bbb"
                +File.separator+"aaa.txt");
        //2.创建outputStream对象(向文件中追加内容)
        try(OutputStream out=new FileOutputStream(file,true)) {
            String msg="\nJava is best";//换行添加内容
            byte[] data=msg.getBytes();
            out.write(data);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //创建inputstream对象
        try(InputStream in=new FileInputStream(file)) {//自动关闭
            //读
            byte[] bytes=new byte[1024];
            int len=in.read(bytes);
            String res=new String(bytes,0,len);
            System.out.println("文件内容为:"+res);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

四、字符流和文件操作

1.字符流类及其子类

说明:

1)CharArrayWriter/CharArrayReader:适配器,把字符数组转换为Writer(Reader),向字符数组中写字符(读取字符)。

2)BufferedWriter/BufferedReader:装饰器,为其它Writer(Reader)提供写(读)缓冲区。

3)StringWriter/StringReader:适配器,把StringBuffer转换为Writer(Reader),向StringBuffer中写字符(读取字符)。

4)PipedWriter/PipedReader:连接一个PipedReader/PipedWriter。

5)FilterWriter/FilterReader:装饰器,扩展其他Writer/Reader功能。

6)PrintWriter:装饰器,输出格式化数据。

7)OutputStreamWriter/InputStreamReader:适配器,将OutputStream转换为Writer(InputStream转换为Reader),可以指定数据汇的字符编码。

8)FileWriter/FileReader:向文件中写字符(读取字符)。

9)PushBackReader:装饰器,能够把读到的一个字符压回到缓冲区中。通常用作编译器的扫描器,在程序中很少用到。

2.字符流中的一些方法

Writer类(与写数据有关的方法):
public void write(char[] cbuf) throws IOException;//写入一个字符数组。 
public abstract void write(char[] cbuf,int off,int len) throws IOException;//写入字符数组的一部分。 
public void write(String str) throws IOException;//写一个字符串 
public void write(String str,int off,int len) throws IOException;//写一个字符串的一部分。
public Writer append(CharSequence csq) throws IOException;//将指定的字符序列附加到此作者。 
public Writer append(CharSequence csq,int start,int end) throws IOException;//将指定字符序列的子序列附加到此作者.
public Writer append(char c) throws IOException;//将指定字符添加到写对象中。
public abstract void flush() throws IOException;//刷新流。一个flush()调用将刷新Writers和OutputStreams链中的所有缓冲区。 
public abstract void close() throws IOException;//关闭流,先刷新。 一旦流已关闭,进一步的write()或flush()调用将导致抛出IOException。 关闭以前关闭的流无效。



Reader类(与读数据有关的方法):
public int read(CharBuffer target) throws IOException;//尝试将字符读入指定的字符缓冲区。 缓冲区用作字符存储库:唯一的更改是put操作的结果。 不执行缓冲器的翻转或倒带。 
public int read() throws IOException;//读一个字符 该方法将阻塞,直到字符可用,发生I / O错误或达到流的结尾。
public int read(char[] cbuf) throws IOException;//将字符读入数组。 该方法将阻塞,直到某些输入可用,发生I / O错误或达到流的结尾。 
public abstract int read(char[] cbuf,int off,int len) throws IOExceptio;//将字符读入数组的一部分。 该方法将阻塞,直到某些输入可用,发生I / O错误或达到流的结尾。 
public long skip(long n) throws IOException;//跳过字符 该方法将阻塞,直到某些字符可用,发生I / O错误或达到流的结尾。 
public boolean ready() throws IOException;//告诉这个流是否准备好被读取。
public boolean markSupported();//告诉这个流是否支持mark()操作。 默认实现始终返回false。 子类应该覆盖此方法。 
public void mark(int readAheadLimit) throws IOException;//标记流中的当前位置。 对reset()的后续调用将尝试将流重新定位到此位置。 并非所有字符输入流都支持mark()操作。
public void reset() throws IOException;//重置流。 如果流已被标记,则尝试在标记处重新定位。 如果流未被标记,则尝试以某种方式对特定流进行重置,例如通过将其重新定位到其起始点。 并不是所有的字符输入流都支持reset()操作,有些支持reset(),而不支持mark()。 
public abstract void close() throws IOException;//关闭流并释放与之相关联的任何系统资源。 一旦流已关闭,进一步的read(),ready(),mark(),reset()或skip()调用将抛出IOException。 关闭以前关闭的流无效。

3.和字符流有关的文件操作

字符适合处理中文数据,有关字符流的定义如下:

public abstract class Writer implements Appendable, Closeable, Flushable;

public abstract class Reader implements Readable, Closeable;

它们也通过继承Closeable接口,间接实现AutoCloseable接口,可以使用try...catch实现自动关闭。Writer类比OutputStream类多继承了Appendable接口,可以实现追加字符。而OutputStream是通过FileOutputStream的构造方法,通过设置append参数为true来实现向文件中追加内容的。

package com.xunpu.myio;

import java.io.*;

public class Test3 {
    public static void main(String[] args) {
        //1.定义file对象
        File file=new File("E:"+File.separator+"JavaFile"+File.separator+"Directory"+File.separator+"bbb"
                +File.separator+"aaa.txt");
        //2.定义writer类对象
        try(Writer writer=new FileWriter(file,true)) {//writer对象自动关闭,向文件中换行添加内容
            writer.append("\nToday is Friday!");
        } catch (IOException e) {
            e.printStackTrace();
        }
        //3.
        try(Reader reader=new FileReader(file)){
            char[] buf=new char[1024];
            int len=reader.read(buf);//将文件的内容存入buf数组中
            String res=new String(buf,0,len);
            System.out.println("文件的内容为:"+res);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值