Java难点重构-IO(上)

简介: 在java 中有输入,输出两种 IO 流,每种输入,输出又分为字节流和字符流两大类。字节又是什么呢,每个字节(byte)右8bit 组成,每种数据类型又几个字节组成。

字符和字节

在java 中有输入,输出两种 IO 流,每种输入,输出又分为字节流和字符流两大类。字节又是什么呢,每个字节(byte)右8bit 组成,每种数据类型又几个字节组成。

字节和字符之间的关系是怎样的呢?

java 采用 unicode 编码,2个字节来表示一个字符,这点与C 语言中不同,C语言中采用 ASCII,在大多数系统中,一个字符通常占1个字节,但是在 0~127 整数之间的字符映射, unicode 向下兼容 ASCII 。而Java 采用unicode 来表示字符,一个中文或英文的 unicode编码都占两个字节。但如果采用其他编码方式,一个字符占用的字节数则各不相同。


例如:Java 中的String 类是按照 unicode 进行编码的,当使用 String(byte[] bytes,String encoding)构造字符串时,encoding 所指的是 bytes 中的数据时按照那种方式编码的,而不是最后产生的 String 是什么编码方式,换句话说,是让系统吧 bytes 中的数据由 encoding 编码方式转换成 unicode 编码。如果不指名,bytes 的编码方式将有 jdk 根据操作系统决定。


getBytes(String charsetName) 使用指定的编码方式将 String 编码为 byte 序列,并将结果存储到 一个 新的 byte 数组中。如果不指定将使用 操作 系统默认的编码方式,我的电脑默认的是 GBK编码。

public class Test {
    public static void main(String[] args) {
       String str="Petterp";
       int byte_len=str.getBytes().length;
       int len=str.length();
        System.out.println("字节长度为"+byte_len);
        System.out.println("字符长度为:"+len);
        System.out.println("系统默认编码方式为:"+System.getProperty("file.encoding"));
    }
}

输出结果:

字节长度为7

字符长度为:7

系统默认编码方式为:UTF-8


在 UTF-8编码中,一个英文字母字符存储需要1个字节,一个汉字字符存储需要3到4个字节。在 UTF-16编码中,一个英文字母字符存储需要两个字节,一个汉字字符储存需要3-4个字节 (Unicode扩展区的一些汉字存储需要4个字节)。在 UTF-32 编码中,世界上任何字符的存储都需要4个字节。


简单来讲,一个字符表示一个汉字或英文字母,具体字符与字节之间的代销比例视编码情况而定。有时候读取的数据是乱码,就是因为编码方式不一致,需要进行转换,然后再按照 unicode 进行编码。

File 类

File 类是 java.io 包下代表与平台无关的文件和目录,也就是说,如果希望在程序中操作文件和目录,都可以通过 File 类来完成。

public class Test {
    public static void main(String[] args) throws IOException {
        //以当前路径来创建一个File 对象
        File file=new File(".");
        //直接获取文件名,输出一点
        System.out.println(file.getName());
        //获取相对路径的父路径可能出错,下面代码输出 null
        System.out.println(file.getParent());
        //获取绝对路径
        System.out.println(file.getAbsoluteFile());
        //获取上一级路径
        System.out.println(file.getAbsoluteFile().getParent());
        //在当前路径下创建一个临时文件
        File tempFile=File.createTempFile("aaa",".txt",file);
        //指定当 JVM 退出时删除该文件
        tempFile.deleteOnExit();
        //以系统当前时间作为新文件名来创建新文件
        File newFile=new File(System.currentTimeMillis()+"");
        System.out.println("newFile对象是否存在:"+newFile.exists());
        //以指定newFile 对象来创建一个文件
        newFile.createNewFile();
        //以newFile对象来创建一个目录,因为newFile 已经存在。
        //所以下面方法返回 false,即无法创建该目录
        newFile.mkdir();
        //使用 list()方法列出当前路径下的所有文件和路径
        String[] fileList=file.list();
        System.out.println("当前路径下所有文件和路径如下==");
        for (String fileName:fileList){
            System.out.println(fileName);
        }
        //listRoots()静态方法列出所有的磁盘根路径
        File[] roots=File.listRoots();
        System.out.println("系统所有根路径如下");
        for (File root:roots){
            System.out.println(root);
        }
    }
}

路径分隔符

windows: “/” " \ " 都可以

linux/unix: “/”

如果windows 选择使用 " \ "做分隔符的话,那么请记得 替换成 ”\“,因为 java 中 ”\“ 代表转义字符,所以推荐都使用 “/” ,也可以直接使用 代码 File.separator ,表示跨平台分隔符

路径

相对路径:

./ 表示当前路径

…/ 表示上一级路径

其中当前路径:默认情况下 ,java.io 包中的类总是根据当前用户目录来分析相对路径名,此目录由系统属性 user.dir 指定,通常是 Java 虚拟机的调用目录。

绝对路径: 绝对路径是完整的路径名,不需要任何其他信息就可以定位自身表示的文件

创建与删除方法
//如果文件存在返回false,否则返回true并且创建文件 
boolean createNewFile();
//创建一个File对象所对应的目录,成功返回true,否则false。且File对象必须为路径而不是文件。只会创建最后一级目录,如果上级目录不存在就抛异常。
boolean mkdir();
//创建一个File对象所对应的目录,成功返回true,否则false。且File对象必须为路径而不是文件。创建多级目录,创建路径中所有不存在的目录
boolean mkdirs()    ;
//如果文件存在返回true并且删除文件,否则返回false
boolean delete();
//在虚拟机终止时,删除File对象所表示的文件或目录。
void deleteOnExit();
判断方法
boolean canExecute()    ;//判断文件是否可执行
boolean canRead();//判断文件是否可读
boolean canWrite();//判断文件是否可写
boolean exists();//判断文件是否存在
boolean isDirectory();//判断是否是目录
boolean isFile();//判断是否是文件
boolean isHidden();//判断是否是隐藏文件或隐藏目录
boolean isAbsolute();//判断是否是绝对路径 文件不存在也能判断
获取方法
String getName();//返回文件或者是目录的名称
String getPath();//返回路径
String getAbsolutePath();//返回绝对路径
String getParent();//返回父目录,如果没有父目录则返回null
long lastModified();//返回最后一次修改的时间
long length();//返回文件的长度
File[] listRoots();// 列出所有的根目录(Window中就是所有系统的盘符)
String[] list() ;//返回一个字符串数组,给定路径下的文件或目录名称字符串
String[] list(FilenameFilter filter);//返回满足过滤器要求的一个字符串数组
File[]  listFiles();//返回一个文件对象数组,给定路径下文件或目录
File[] listFiles(FilenameFilter filter);//返回满足过滤器要求的一个文件对象数组

文件过滤器

上卖弄方法其中包含了一个重要的接口FileNameFilter,该接口是个文件过滤器,包含了一个accept(File dir,String name)方法,该方法依次对指定File的所有子目录或者文件进行迭代,按照指定条件,进行过滤,过滤出满足条件的所有文件。

public class Test {
    public static void main(String[] args) throws IOException {
        //以当前路径来创建一个File 对象
        File file=new File(".");
        //创建临时文件
        File tempFike=File.createTempFile("aaa",".java",file);
        //虚拟机退出时删除该文件
        tempFike.deleteOnExit();
        //文件过滤:如果文件名以.java结尾,或者文件对应一个路径,则返回true
        String [] namList=file.list(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(".java");
            }
        });
        //new File(name).isDirectory()  测试文件是否为目录
        String[] namList2=file.list((dir,name)->name.endsWith(".java")||new File(name).isDirectory());
        //遍历
        for (String name:namList2){
            System.out.println(name);
        }
    }
}

IO流

概念

Java 的 IO 流是实现输入/输出的基础,他可以方便的实现数据的输入/输出操作,在 Java 中 把不同的 输入/输出源抽象表达为 “流”,流是一组有顺序,有起点和终点的字节集合,是对数据传入的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传入特性将流抽象为各种类,方便更直观的进行数据的操作。

流有输入和输出,输入时是流从数据源流向程序。输出是时从程序传向数据源,而数据源可以是内存,文件,网络或程序等


IO流的分类

输入流和输出流

输入流与输出流是以 内存的角度来考虑。

  1. 输入流:只能从中读取数据,而不能向其写入数据。
  2. 输出流:只能向其写入数据,而不能从中读取数据。


如下如所示:对程序而言,向右的箭头,表示输入,向左的箭头,表示输出。


网络异常,图片无法展示
|

字节流和字符流

字节流和字符流用法几乎一样,区别在于字节流和字符流所操作的数据单元不同。


字符流的由来:因为数据编码的不同,而又了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。字节流和字符流的区别:


  1. 读写单位不同:字节流以字节(8bit) 为单位,字符流以字符(16bit)为单位,根据码表映射字符,一次可能读多个字节。
  2. 处理对象不同:字节流能处理所有类型的数据(如图片,avi等),而字符流只能处理字符类型的数据。


只要是处理纯文本数据,就优先考虑使用字符集。除此之外都使用字节流。


字节流和处理流


按照流的角色来分,可以分为节点流和处理流。


可以从/向一个特定的 IO 设备(如磁盘,网络) 读/写 数据的流,称为节点流,节点流也被称为低级流。


处理流是对一个已存在的流进行连接或封装,通过封装后的流来实现数据读/写功能,处理流也被称为高级流

//节点流,直接传入的参数是 IO 设备
FileInputStream fis=new FileInputStream("test.text");
//处理流,直接传入的参数是流对象
BufferedInputStream bis=new BufferedInputStream(fis);


当使用处理流进行输入输出是,程序并不会直接连接到实际的数据源,没有和实际的输入/输出节点连接。使用处理流的一个明显好处是,只要使用相同的处理流,程序就可以采用完全相同的输入/输出 代码来访问不同的数据源,随着处理流所包装节点流的变化,程序实际所访问的数据源也相应的发生变化。


实际上,Java使用处理流来包装节点流是一种典型的装饰器设计模式,通过使用处理流来包装不同的节点流,即可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入/输出的功能。因此处理流也被称为包装流。

目录
相关文章
|
1月前
|
存储 Java 数据处理
|
1月前
|
Java API
java中IO与NIO有什么不同
java中IO与NIO有什么不同
|
20天前
|
存储 Java
探索 Java IO 流的多种实现方式
【4月更文挑战第4天】Java IO 流是处理输入输出的关键组件,包括文件流(FileInputStream/FileOutputStream)、字符流(FileReader/FileWriter)、缓冲区流(BufferedInputStream/BufferedOutputStream)、转换流(InputStreamReader/OutputStreamWriter)、数据流(DataInputStream/DataOutputStream)、对象流(ObjectInputStream/ObjectOutputStream)、随机访问文件流(RandomAccessFile)和管道流。
|
1月前
|
Java 关系型数据库 MySQL
Flink1.18.1和CDC2.4.1 本地没问题 提交任务到服务器 报错java.lang.NoClassDefFoundError: Could not initialize class io.debezium.connector.mysql.MySqlConnectorConfig
【2月更文挑战第33天】Flink1.18.1和CDC2.4.1 本地没问题 提交任务到服务器 报错java.lang.NoClassDefFoundError: Could not initialize class io.debezium.connector.mysql.MySqlConnectorConfig
50 2
|
1月前
|
Java
|
2月前
|
Java 数据处理
如何玩转Java IO?
【2月更文挑战第7天】
219 0
如何玩转Java IO?
|
2月前
|
缓存 分布式计算 Java
Java基础深化和提高-------IO流
Java基础深化和提高-------IO流
108 0
|
3月前
|
存储 Java 数据安全/隐私保护
从零开始学习 Java:简单易懂的入门指南之IO字符流(三十一)
从零开始学习 Java:简单易懂的入门指南之IO字符流(三十一)
|
3月前
|
存储 移动开发 Java
从零开始学习 Java:简单易懂的入门指南之IO字节流(三十)
从零开始学习 Java:简单易懂的入门指南之IO字节流(三十)
|
3月前
|
存储 网络协议 Java
Java学习—IO流
Java学习—IO流