javaIO

在java中,IO是一种阻塞式IO(BIO),基于抽象类,将具体的IO操作放在子线程中进行。

核心有五个类:File、InputStream、OutputStream、Reader、Writer 和一个接口:Serializable

这其中InputStream、OutputStream、Reader、Writer 都是抽象类,要使用的话应该看具体对什么进行操作,比如说对文件操作,就要实例化一个文件字节或字符流,如:InputStream in = new FileInputStream();

一、File类

File类是唯一一个与文件本身操作(创建、删除、取得信息)有关的程序类,他既可以描述文件也可以描述文件夹

产生File对象

    public File(String pathname):根据文件的绝对路径来产生file对象
    public File(URI uri):根据网络产生file对象

1、常用操作方法

    1)创建新文件:
        public boolean createNewFile() throws IOException
    2)判断文件是否存在
        public boolean exists()
    3)删除文件
        public boolean delete()
    文件分隔符:
        File.separator :不同的操作系统有不同的分割符,比如Windows下是“\”,而Linux下是"/",为了程序的移植性更好,引入了 File.separator ,将需要写分隔符的地方换成 File.separator ,就能在不同的操作系统下产生不同的分隔符。

2、目录操作

    1)取得父路径的File对象
        public File getParentFile()
    2)取得父路径的目录
        public String getParent()
    3)创建多级父路径(一次性创建多级不存在的父路径)
        public boolean mkdirs()

public class Test {
    public static void main(String[] args) {
        File file = new File("C:"+File.separator+"Users"
                +File.separator+"Eve"+File.separator+
                "Desktop"+File.separator+
                "java"+File.separator+"javaIO.java");
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        if(!file.exists()){
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else {
            System.out.println("文件已经存在");
        }
    }
}

这段代码作用是在桌面创建一个java文件夹,在java文件夹中创建一个名为javaIO.java的文件。如果文件存在就输出文件已经存在。这段代码先进行对父路径的的判断,如果父路径不存在一定要使用mkdirs()创建父路径,否则createNewFile不会创建父路径,程序就会报错,提示找不到指定路径。

3、取得文件信息
    1)判断File对象是否是文件
        public boolean isFile()
    2)判断File对象是否是文件夹
        public boolean isDirectory()
    3)取得文件大小---单位是字节
        public long length()
    4)取得上次修改时间
        public long lastModified()
    5)列出一个目录的全部组成
        public File[] listFiles()

4、遍历指定目录下所有的文件(包括子目录)

了解了这些我们可以写一段代码来数一数电脑中有多少文件,当然这个时间是非常长的,我们可以选择一个文件夹来数一数有多少文件。大体思路是选择一个目录,判断他是目录还是文件夹,是文件计数器就+1,是目录的话就取得这个目录的全部组成,再通过递归来不断深入直到遍历完所有文件。

public class Test{
    static int count = 0;
    public static void main(String[] args) {
        File file = new File("D:\\");
        new Thread(()->{
            long start = System.currentTimeMillis();
            findAllFile(file);
            long end = System.currentTimeMillis();
            System.out.println("共计"+(end - start)+"毫秒");
            System.out.println(count);
        }).start();

    }
    public static void findAllFile(File file){
        if(file.isFile()){
            System.out.println(file);
            count++;
        }else {
            if(file.exists() && file.isDirectory()){
                File[] files = file.listFiles();
                if (files!=null) {
                    for (File file1 :
                            files) {
                        findAllFile(file1);
                    }
                }
            }
        }
    }
}

有些人写这样的代码的时候可能会遇到空指针异常,原因在于有些系统的文件我们无权访问,所以在获取目录的全部组成的时候要判断一下取得的files是不是空的。               

File[] files = file.listFiles();
                if (files!=null) {
                    for (File file1 :
                            files) {
                        findAllFile(file1);
                    }
                }

二、字节与字符流

java.io包中流分为两类:输入流与输出流

字节(byte)流是原生操作,无需转换,可以处理文本文件、图像、音乐、视频等资源,如InputStream、OutputStream
字节(char)流是字节流经过处理后的操作,只用于处理中文文本,如Reader、Writer

流模型的操作流程

1)取得终端对象
2)根据终端对象取得输入输出流
3)根据输入输出流进行数据读取与写入
4)关闭流(IO属于资源处理,所有的资源处理(IO操作,数据库操作,网络操作)在使用后一定要关闭

2.1、字节输出流(OutputStream)

核心方法

Write()方法
    public void write(byte b[]):将给定的字节数组全部输出
    public void write(byte b[], int off, int len) throws IOException:将给定的字节数组以off位置开始输出len长度后停止输出
    public abstract void write(int b) throws IOException: 输出单个字节

使用OutputStream输出数据时,若指定的文件不存在,FileOutputStream会自动创建文件(不包含创建目录),使用OutputStream输出内容时,默认是文件内容的覆盖操作.若要进行文件内容的追加,使用如下构造方法public FileOutputStream(String name, boolean append)

2.2、字节输入流(InputStream)

    核心方法
        public int read(byte b[]) throws IOException:将读取的内容放入字节数组中

这个方法有一个int类型的返回值,返回值代表的含义如下:
        I.返回b.length
            表明未读取的数据大于存放的缓冲区大小,返回字节数组大小
        II.返回大于0的整数,此整数小于b.length
            表明未读取的数据小于存放的缓冲区大小,返回剩余数据大小
        III.返回-1 --- 终止标记
            此时数据已经读取完毕

这个很好理解,假设把byte[] b当做一个勺子,把要读取的东西当做一碗饭,read方法就是我用勺子去碗里盛饭的过程,我盛了一勺饭,但是碗里还有很多饭,就返回我一勺取得饭的数量,即b.length,当我继续盛直到碗里剩下的饭不足一勺了,这时返回的是碗里剩的饭的数量,我把碗里的饭盛完了,就返回-1。

public class Test {
    public static void main(String[] args) throws Exception{
        //1.取得终端对象
        File file = new File("C:"+File.separator+"Users"+File.separator+"Eve"+File.separator
                +"Desktop"+File.separator+"test.txt");
        //2.取得指定文件的输出流
        OutputStream out = new FileOutputStream(file,true);
        String str = "字节输出流";
        //3.进行数据输出
        out.write(str.getBytes());
        //4.关闭流
        out.close();
        InputStream in = new FileInputStream(file);
        byte[] b = new byte[1024];
        while (in.read(b) != -1){
            System.out.print(new String(b));
        }
        in.close();
    }
}

这里我设置字节数组的大小是1024,大一点没有关系,但要是设置太小,比如说1,就会出现乱码的问题,这是由于数据丢失造成的,因为在UTF-8编码中,一个汉字不可能是一个字节可以存下的,由于UTF-8是变长的,一个汉字可能占3个或4个字节。

看一下输出,当字节数组大小是1024时,

当字节数组大小是1时

当字节数组大小是2时

当字节数组大小是3时

可见这几个汉字都是3个字节。

2.3、字符输出流Writer---适用于处理中文文本

核心方法
     public void write(String str) throws IOException
     字符流可以直接支持字符串的输出
     字符流若未关闭,数据在缓冲区存放,不会输出到目标终端.要想将数据输出,要么将输出流关闭,要么使用flush()强制刷新缓冲区

2.4、字符输入流Reader
    public int read(char cbuf[]) throws IOException

字符输入输出流使用方式与字节输入输出流的使用大同小异,只不过字符输入输出流支持字符串的输出,不用转换成字节数组,对中文的输入输出方便了一下。

三、转换流(字节流--->字符流)

字符流的具体子类大都是通过转换流将字节流转换为字符流(FileWriter基础转换流)

    OutputStreamWriter(字节输出流--->字符输出流)

    InputStreamReader(字节输入流--->字符输入流)

转换流只是一个中间的媒介,具体使用较少,比如我可以这样使用:

Writer writer = new OutputStreamWriter(new FileOutputStream(file));

Writer writer = new FileWriter(file);

的效果是一样的

四、内存流(以内存为终端的输入输出流)

字节内存流
    ByteArrayInputStream,ByteArrayOutputStream
字符内存流
    CharArrayReader,CharArrayWriter

将指定的字节数组的内容放到内存中
    public ByteArrayInputStream(byte buf[])

    public ByteArrayOutputStream()

通过内存流实现大小写转换

public class Test {
    public static void main(String[] args) throws Exception{
        String str = "HELLO WORLD";
        InputStream in = new ByteArrayInputStream(str.getBytes());
        OutputStream out = new ByteArrayOutputStream();
        int temp = 0;
        while ((temp = in.read())!=-1){
            out.write(Character.toLowerCase(temp));
        }
        System.out.println(out);
    }
}

五、打印流和装饰设计模式

    字节打印流:PrintStream
    字符打印流:PrintWriter

打印流是针对输出流的强化版本,不需要考虑OutputStream的write方法只能接受byte数组或int类型的数据,打印流几乎可以支持所有的数据类型。

        PrintStream printStream = new PrintStream(file);
        printStream.print("这是打印流");
        printStream.close();

比如我们可以直接给通过PrintStream类的print方法进行写入一个字符串。

我们看一下print方法可以传入的数据类型

    打印流的设计属于装饰设计模式---基于抽象类
    特点:核心依然是某个类(OutputStream提供的writer())的功能。但是为了得到更好的操作效果,让其支持的功能更多一些,使用装饰类(PrintStream)
    优点:很容易更换装饰类来达到不同的操作效果
    缺点:由于装饰设计模式的引入,造成类结构的复杂

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值