Java中的File及I/O流

Java中的File及I/O流

File对象

File类代表文件(文件和目录)

存储介质中的文件和目录在Java程序中都是用File类的实例来表示

常用构造方法:

public File(String pathname):以pathname为路径创建File对象
    pathname为一个具体路径:
    1. 绝对路径 完整的路径 含有其实盘符到最终的目标文件/目录
	优点:在当前系统中任何地方都可以直接定位到目标
	缺点:不利于移植
    2. 相对路径 相对一个参照路径(基准路径) 使用 . 或者 .. 进行路径的映射
	优点: 利于移植
	缺点: 基准路径不固定  

在项目中建议固定基准路径之后可以使用相对路径进行定位

File类的一个常用属性

public static final String separator存储了当前系统的路径分隔符 在 UNIX 系统上,此字段的值为 ‘/’;在 Windows 系统上为 ‘’

为了程序的跨平台特性,文件的路径应该用这个属性值来代表。或则都使用’/‘进行分隔 因为windows 对’/'有兼容性

常用方法

访问File对象的属性:

•public boolean canRead()
    •public boolean canWrite()
    •public boolean exists()
    •public boolean isDirectory()
    •public boolean isFile()
    •public boolean isHidden()
    •public long lastModified() //毫秒值
    •public long length() //以字节为单位
    •public String getName() //获取文件名
    •public String getPath() //路径名
    •public String getAbsolutePath() //返回此File对象的绝对路径名
    •public File getAbsoluteFile() •public String getCanonicalPath() //返回此File对象的规范路径名字符串
    •public File getCanonicalFile() //返回此File对象的规范形式
    •public String getParent() //返回父目录的路径名字符串
    •public URI toURI() //返回此文件的统一资源标识符名

代码举例如下:

import java.io.File;
public class FileTest{
    public static void main(String[] args){
        File file = new File(args[0]);
        System.out.println("文件或目录是否存在:" + file.exists());
        System.out.println("是文件吗:" + file.isFile());
        System.out.println("是目录吗:" + file.isDirectory());
        System.out.println("名称:" + file .getName());
        System.out.println("路径: " + file.getPath());
        System.out.println("绝对路径: " + file.getAbsolutePath());
        System.out.println("最后修改时间:" + file.lastModified());
        System.out.println(“文件大小:+ file.length()+ “ 字节”);
        ……
    }
}

对File对象的具体操作:

•浏览目录中的子文件和子目录
    •public String[] list() //返回此目录下的文件名和目录名的数组
    •public File[] listFiles()//返回此目录下的文件和目录File实例数组
    •public File[] listFiles(FilenameFilter filter) //返回此目录中满足指定过滤器的文件和目录
    •java.io.FilenameFilter接口:实现此接口的类实例可用于过滤文件名
    •对文件的操作:
    •public boolean createNewFile() //不存在时创建此文件对象所代表的空文件
    •public boolean delete() //删除文件或目录。目录必须是空才能删除
    •public boolean mkdir() //创建此抽象路径名指定的目录
    •public boolean mkdirs() //创建此抽象路径名指定的目录,包括所有必需但不存在的父目录
    •public boolean renameTo(File dest) //重命名

用递归算法列出指定目录下的所有子孙文件和目录 :

package file;
/*
* 将某个目录所有下属目录或文件 全部遍历出来
* */
import java.io.File;
public class LookDir {
    public static final String SYMBOL = "|--";
    public static void main(String[] args) {
        String path = "D:/iotest";
        lookSome(new File(path),1);
    }
    public static void lookSome(File file,int level){
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < level ; i++) {
            sb.append(SYMBOL);
        }
        System.out.println(sb.toString()+file.getName());
        //判断当前是否是目录
        if(file.isDirectory()){
            //如果是目录 再进行遍历
            File[] fs = file.listFiles();//获取当前目录的所有子元素
            for(File f : fs){
                //遍历当前子元素
                if(f.isFile()){
                    System.out.println(sb.toString()+f.getName());//出口
                }else{
                    lookSome(f,++level);//使用递归来进行文件结构的查看
                }
            }
        }else{
            //如果是文件 则直接输出文件名
            System.out.println(sb.toString()+file.getName());//出口
        }
    }
}

列出指定目录下的jpg类型图片:

import java.io.File;
import java.io.FileFilter;
public class FileFilterTest {
    public static void main(String[] args) {
        /*
File 对象可以获取当前目录下的指定文件 --- 可以进行文件过滤
*/
        File f = new File("D:/iotest");
        File[] fs = f.listFiles();
        for(File f1 : fs){
            System.out.println(f1.getName());
        }
        //需求只希望看到当前目录下的所有.jpg文件
        File[] fs1 = f.listFiles(new FileFilter() {
            @Override删除一个目录的过程是如何进行的?--用递归删除一个非空目录
                public boolean accept(File ff) {
                if (ff.getName().endsWith(".jpg")) {
                    return true;
                } else {
                    return false;
                }
            }
        });
        System.out.println("~~~~~~~~~~~~~~~~~");
        for(File f1 : fs1){
            System.out.println(f1.getName());
        }
    }
}

删除一个目录的过程是如何进行的?–用递归删除一个非空目录:

package file;
import java.io.File;
/*
删除指定目录/文件
核心思想
文件直接删除 如果是目录 必须进行判定 是空目录才能删除
否则需要先删除其内部的所有文件 之后再删除该目录
*/
public class DeleteDir {
    public static void main(String[] args) {
        String path = "D:/iotest";
        deleteDir(new File(path));
    }
    public static void deleteDir(File file){
        if(null == file ){
            System.out.println("目标文件不存在,请检查");
        }else{
            if(file.isDirectory()){
                //清空当前目录下的所有元素
                File[] fs = file.listFiles();
                for(File f : fs){
                    if(f.isFile()){
                        //下属元素是文件 直接删除
                        f.delete();
                    }else{
                        //如果是目录 使用递归方式将该目录当做参数 传递给删除方法
                        deleteDir(f);
                    }
                }
            }
            file.delete();//删除当前目标元素
        }
    }
}

输入/输出的基本原理

数据流(Stream)是指数据通信的通道。

数据流(Stream)是指数据通信的通道。 java程序中对数据的输入、输出操作是以“流”方式进行的。JDK中提供了各式的“流”类来获取不同种类的 数据。在这里插入图片描述

流的概述

  • 按照方向区分
    1. 输入流 程序可以从中读取数据的流
    2. 输出流 程序能向其中写出数据的流
  • 按照传输单位区分
    1. 字节流 底层以字节方式传输 可以传输任何类型的文件
    2. 字符流 底层以字符方式传输 只能传输纯文本类型的文件
  • 按照功能区分
    1. 节点流 源空间到目标空间的底层数据通道
    2. 节点流 源空间到目标空间的底层数据通道

Java中对于流的处理类

在Java中按照方向和传输单位两个维度 提供了4大抽象类

字节字符
输入InputStreamReader
输出OutPutStreamWriter

InputStream抽象类

继承自InputStream的流都是用于向程序中输入数据的,且数据的单位为字节(8位)。(粉色为节点 流,蓝色为过滤流)
在这里插入图片描述

InputStream的常用方法

public abstract int read() throws IOException
从输入流中读取数据的下一个字节, 返回读到的字节值。若遇到流的末尾,返回-1public int read(byte[] b) throws IOException
从输入流中读取b.length个字节的数据并存储到缓冲区数组b中。返回的是实际读到的字节总数。若遇
到流的末尾,返回-1public int read(byte[] b, int off, int len) throws IOException
读取 len 个字节的数据,并从数组b的off位置开始写入到这个数组中
•public void close() throws IOException
关闭此输入流并释放与此流关联的所有系统资源
•public int available() throws IOException
返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数
•public skip(long n) throws IOException
跳过和丢弃此输入流中数据的 n 个字节,返回实现路过的字节数。

OutputStream抽象类

继承自OutputStream的流是程序用于向外输出数据的,且数据的单位为字节(8位)。
在这里插入图片描述
OutPutStream基础方法

public abstract void write(int b) throws IOException
将指定的字节写入此输出流
•public void write(byte[] b) throws IOException
将 b.length 个字节从指定的 byte 数组写出到此输出流
•public void write(byte[] b, int off, int len) throws IOException
将指定 byte 数组中从偏移量 off 开始的 len 个字节写出此输出流
•public void flush() throws IOException
刷新此输出流并强制写出所有缓冲的输出字节
•pulbic void close() throws IOException
关闭此输出流并释放与此流有关的所有系统资源

Reader抽象类

继承自Reader的流都是用于向程序中输入数据的,且数据的单位为字符(16位)。
在这里插入图片描述

Reader常用方法

public int read() throws IOException
读取单个字符,返回作为整数读取的字符,如果已到达流的末尾返回-1public int read(char[] cbuf) throws IOException
将字符读入数组,返回读取的字符数;否则返回-1public abstract int read(char[] cbuf, int off, int len) throws IOException
读取len个字符,并从数组cbuf的off位置开始写入到这个数组中
•public abstract void close() throws IOException
关闭该流并释放与之关联的所有资源
•public long skip(long n) throws IOException
跳过n个字符。

Writer抽象类

继承自Writer的流是程序用于向外输出数据的,且数据的单位为字符(16位)。
在这里插入图片描述

Writer的基础方法

public void write(int c) throws IOException
写入单个字符
•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 abstract void flush() throws IOException
刷新该流的缓冲,将缓冲的数据全写到目的地
•public abstract void close() throws IOException
关闭此流,但要先刷新它

文件流

主要用来操控文件的读写,可以用来复制文件或者剪切。

专门用于操作文件的流。Java SE API中提供了4种:

  • FileInputStream继承自InputStream
  • FileOutputStream继承自OutputStream
  • FileReader继承自Reader
  • FileWriter继承自Writer

二进制文件(字节文件):图片、音频、视频等。 需要使用字节流来操作

文本文件(字符文件):.txt、.properties、.xml、.html 字符或字节都可以操作 但建议适应字符操作 很简便

注:文件续写问题 在文件写出时 如果该输出流的构造器第二个参数为true 则会自动续写 如果为false或 者不写第二个参数 则直接覆盖原文件所有内容

/*
使用字节流完成文件复制的功能
*/
int b = 0;
FileInputStream in = null;
FileOutputStream out = null;
try {
    in = new FileInputStream("d:/IOTest/soruce.jpg");
    out = new FileOutputStream("d:/IOTest/dest.jpg");
    while ((b = in.read()) != -1) { //有没有效率更高的方式?
        out.write(b);
    }
    System.out.println("文件复制成功");
} catch (FileNotFoundException e) {
    System.out.println("找不到指定文件");
    e.printStackTrace();
} catch (IOException e) {
    System.out.println("文件复制错误");
    e.printStackTrace();
}finally{}

缓存流 – 过滤流

缓冲流是建立在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写的效率,还增加了一 些新的方法。Java SE API提供四种缓冲流

  • BufferedInputStream 可以对任何的InputStream流进行包装(套接)

  • BufferedOutputStream 可以对任何的OutputStream流进行包装(套接)

  • BufferedReader 可以对任何的Reader流进行包装

    新增了readLine()方法用于一次读取一行字符串(’\r’或’\n’作为行结束)

  • BufferedWriter 可以对任何的Writer流进行包装

    新增了newLine()方法用于写入一个行分隔符。

注意:

1.对于缓冲输出流,写出的数据会先缓存在内存缓冲区中,关闭此流前要用flush()方法将缓存区的数据 立刻写出。

2.关闭过滤流时,会自动关闭过滤流所包装(套接)的所有底层流。

BufferedInputStream bis = null;
BufferedOutputStream bos = null;
byte[] buf = new byte[1024];
try{
    bis = new BufferedInputStream(new FileInputStream(src));
    bos = new BufferedOutputStream(new FileOutputStream(dest));
    for(int len = 0; (len = bis.read(buf)) != -1;){
        bos.write(buf, 0, len);
    }
    bos.flush();
}catch(IOException e){
    e.printStackTrace();
}finally{
    if(bos != null){
        try {bos.close();} catch (IOException e) {e.printStackTrace();}
    }
    if(bis != null){
        try {bis.close();} catch (IOException e) {e.printStackTrace();}
    }
}

转换流——过滤流

转换流用于在字节流和字符流之间转换。JaveSE API提供了两种转换流:

  • InputStreamReader需要和InputStream“套接”,它可以将字节流中读入的字节解码成字符
  • OutputStreamWriter需要和OutputStream“套接”,它可以将要写入字节流的字符编码成字节

转换流常用于:

  • 解决乱码问题
  • 网络编程中,只提供字节流。
System.out.println("请输入信息(退出输入e):");
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = null;
try {
    while ((s = br.readLine()) != null) { //阻塞程序
        if (s.equals("e")) {
            System.out.println("安全退出!!");
            break;
        }
        System.out.println("-->:"+s.toUpperCase());
        System.out.println("继续输入信息");
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    try { if (null != br) { br.close(); } } catch (IOException e)
    { e.printStackTrace(); }
}

对象流

用于存储和读取基本类型数据或对象的过滤流

  • ObjectOutputStream保存基本类型数据或对象:序列化
  • ObjectInputStream读取基本类型数据或对象:反序列化

能被序列化的对象所对应的类必须实现java.io.Serializable这个标识性接口

package serialized;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SeriaillzedTest {
    public static void main(String[] args) {
        /*
在java中有一个流 ObjectStream 对象流 能够将对象序列化
序列化 就是将程序中的对象或者信息 持久化(本地存储)
可以通过序列化 和反序列化将一个对象 转换成一个文件 之后再从文件中读取还原成一个对象
底层就可以通过文件来传输该对象的信息
示例:将一个学生类 序列化成一个文件
*/
        Student stu = new Student("王源", 20);
        xlh(stu);
        fxlh();
    }
    public static void xlh(Student stu) {
        File f = new File("D:/iotest/stu.dat");
        ObjectOutputStream oo = null;
        try {
            oo = new ObjectOutputStream(new FileOutputStream(f));
            oo.writeObject(stu);
            oo.writeBoolean(true);
            oo.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (oo != null) {
                try {
                    oo.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void fxlh() {
        File f = new File("D:/iotest/stu.dat");
        ObjectInput oi = null;
        try {
            oi = new ObjectInputStream(new FileInputStream(f));
            Student stu = (Student) oi.readObject();
            System.out.println(stu);
            boolean b = oi.readBoolean();
            System.out.println("booelan=" + b);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

序列化的相关问题

transient关键字修饰成员变量时,表示这个成员变量是不需要序列化的。

实现了Serializable接口的类都应该生成一个private static final long serialVersionUID 序列化版本ID 作为标识。

其他流

  • 其他流

    DataInputStream和DataOutputStream

  • 打印流

    PrintStream和PrintWriter都属于打印流 它们的输出操作永远也不会抛出IOException

  • 随机访问文件

    RandomAccessFile类,自身具备读写的方法

    void seek(long pos); //文件指针移动到指定的指针偏移量

    long getFilePointer(); //获取当前文件指针偏移量

    int read(byte[] b); //读数据

    void write(byte[] b, int off, int len); //写数据

try-with-resources语句

JDK7中提供的,它可以自动关闭相关的资源的语法:

try (资源声明1; 资源声明2;) {}catch(){
}

资源是指实现了java.lang.AutoCloseable或java.io.Closeable的类的对象。如:InputStream、 OutputStream、Reader、Writer、Connection、ResultSet等。

它会确保在本语句结束时关闭try语句中声明的所有资源。资源被关闭的顺序与它们被创建的顺序相反。

public static void copy(File src, File dest){
    byte[] buf = new byte[1024];
    try(BufferedInputStream bis = new BufferedInputStream(new
                                                          FileInputStream(src));
        BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(dest)))
    {
        for(int len = 0; (len = bis.read(buf)) != -1;){
            bos.write(buf, 0, len);
        }
        bos.flush();
    }catch (Exception e) {
        e.printStackTrace();
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

于歌852

您的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值