Java 的 IO 四大基类详解(上)
来源:互联网 发布:ddos网络攻击 编辑:程序博客网 时间:2024/06/10 06:26
1、概述
Java 的IO通过java.io 包下的类和接口来支持,java.io包下主要包括输入、输出两种流。每种输入输出流又可分为字节流和字符流两大类。
字节流以字节为单位处理输入、输出操作;
字符流以字符来处理输入、输出操作。
2、File类
File类代表与平台无关的文件和目录,他可以操作文件或目录,比如 File能新建、删除、重命名文件和目录,File类不能访问文件本身。如果要访问文件本身,则使用输入/输出流。
下面测试一下File类的功能。
/** * Created by 杨Sir on 2017/10/30. * 该类测试了 File类的常用方法 */public class FileTest { public static void main(String[] args) throws IOException { //以当前路径来创建一个File对象 File file2 = new File("."); //直接获取文件名 System.out.println(file2.getName()); //获取文件相对路径的父路径,可能出错,下面返回 null System.out.println(file2.getParent()); //获取绝对路径 System.out.println(file2.getAbsoluteFile()); //获取上一级路径 System.out.println(file2.getAbsoluteFile().getParent()); System.out.println("-------------------------------------------"); //以指定路径来创建一个File对象,例如项目中的 file/file2 文件夹为指定路径 File file0 = new File("file/file2"); /** * 在指定的路径下创建一个临时文件,,文件存放位置 file0对象对应的路径下 * 使用前缀,系统随机生成的随机数和给定的后缀 作为文件名。 这是一个静态方法 */ File tmpFile = File.createTempFile("aaa",".txt",file0); //指定JVM退出时删除该文件,钩子方法 tmpFile.deleteOnExit(); System.out.println("tmpFile 被删除..."); System.out.println("-------------------------------------------"); //以系统当前时间为新文件名来创建新文件 File newFile = new File(System.currentTimeMillis() + ""); System.out.println("newFile对象是否存在: "+ newFile.exists()); //返回false //以指定的newFile对象来创建一个文件 ,文件位置在项目名下 newFile.createNewFile(); //以newFile对象创建一个目录,因为newFile已存在,因此下面方法返回false,无法创建 System.out.println(newFile.mkdir()); /** * 使用list方法列出当前路径下所有文件和路径 * 项目名下的所有文件及路径(不包括路径的子路径) */ String[] fileList = file2.list(); for(String fileName : fileList){ System.out.println(fileName); } System.out.println("-----------------------"); //listRoots()静态方法列出所有的磁盘根路径: C:\ D:\ E:\ F:\ File[] roots = File.listRoots(); for(File file : roots){ System.out.println(file); } }}
需要注意的是:windows的路径分割符为反斜线(\), 而Java中反斜线是转义字符,因此windows下应该写两条反斜线(\),例如 F:\abc\test.txt。或者使用斜线(/),java支持将斜线当做平台无关的路径分割符。
File类的list方法可以接收一个FilenameFilter参数,用于文件过滤。这里的FilenameFilter接口是一个函数式接口,里面包含一个accept(File dir, String name)方法。举例如下:
/** * Created by 杨Sir on 2017/10/30. * 文件过滤器的使用 */public class FilenameFilterTest { public static void main(String[] args){ File file = new File("."); /** * 使用Lambda表达式实现文件过滤器 * accept方法将对指定File的所有 子目录或文件进行迭代,如果方法返回true,则list()会列出该子目录或文件 * 如果文件以 .java结尾或文件对应一个路径,则返回true */ String[] nameList = file.list(((dir, name) -> name.endsWith(".java") || new File(name).isDirectory())); //当前路径(创建nameList对象的路径)下所有的.java文件和文件夹将被输出 for (String name : nameList){ System.out.println(name); } }}
3、理解 Java 的 IO 流
3.1 Java的 io流是实现输入输出的基础,Java把不同的输入输出源抽象为流。正因为流的抽象,才可以通过一致的IO代码去读写不同的IO流节点。
流的分类:
1.从内存的角度来看
– 输入流:只能从中读取数据,而不能向其写入数据
– 输出流:只能向其写入数据,而不能从中读取数据
java的输入流主要由 InputStream 和 Reader作为基类,而输出流主要以 OutputStream 和 Writer作为基类,这些基类无法创建实例。
2. 字节流和字符流
字节流和字符流的区别在于所操作的数据单元不同,字节流操作的数据单元是8位的字节,字符流操作的数据单元是16位的字符。
字节流主要由 InputStream 和 OutputStream作为基类,字符流主要有 Reader 和 Writer作为基类。如下图:
3. 节点流和处理流(按流的角色分):
从/向 一个特定的IO设备(磁盘、网络)读/写数据的流,称为节点流,当使用节点流时,程序直接连到实际的数据源,和实际的输入/输出节点连接。
处理流用于对一个已存在的流进行连接或封装,通过封装后的流实现读/写功能。
使用处理流的好处是:只要使用相同的处理流,程序就可以采用完全相同的输入/输出代码访问不同的数据源,随着处理流包装节点流的变化,程序实际访问的数据源也在变化。Java用处理流包装节点流是一个典型的装饰器模式。
3.2 字节流和字符流
我们先来看看InputStream 和 Reader
InputStream 和 Reader是所有输入流的抽象基类,他们是所有输入流的模板,提供通用方法。
①. InputStream包含三个方法:
int read(): 从输入流读取单个字节,返回读取的字节数据,字节数据可直接转换为 int类型。
int read(byte[] b): 从输入流中最多读取 b.length 个字节的数据,并将其存入数组b中,返回实际读取的字节数。
int read(byte[] b, int off, int len): 从输入流中最多读取 len 个字节的数据,并将其存入数组b中,从off位置开始读,返回实际读取的字节数。
②. Reader包含的三个方法:
int read(): 从输入流读取单个字符,返回读取的字符数据,字符数据可直接转换为 int类型。
int read(char[] b): 从输入流中最多读取 b.length 个字符的数据,并将其存入数组b中,返回实际读取的字符数。
int read(char[] b, int off, int len): 从输入流中最多读取 len 个字符的数据,并将其存入数组b中,从off位置开始读,返回实际读取的字符数。
要注意:当read(char[] c) 或 read(byte[] b)方法返回 -1,表明到了输入流的结束点。
前面说过,InputStream 和 Reader都不能创建实例,那怎么办呢?没关系,他们各自提供了一个用于读取文件的输入流:FileInputStream 和 FileReader,他们都是节点流,会直接和指定文件关联。 例如使用FileInputStream 来读取文件本身数据。
/** * Created by 杨Sir on 2017/10/30. * 通过FileInputStream 来读取文件数据 * 采用字节读取,注释可能会乱码,因为文本保存时采用GBK编码,一个中文字符占两个字节,如果read只读到半个字节,就会乱码。 */public class FileInputStreamTest { public static void main(String[] args) throws IOException { //创建字节输入流,相当于从管道中取数据,,绝对路径 FileInputStream fis = new FileInputStream("D:\\绝对路径\\FileInputStreamTest.java"); //相对路径// FileInputStream fis = new FileInputStream(".\\src\\相对路径\\FileInputStreamTest.java"); //创建一个长为1024个字节的管道 byte[] buf = new byte[1024]; //用于保存实际读取的字节数 int hasRead = 0; //读取1024字节之后会进行输出,然后再次读取时,读取剩余的字节,在输出,直到没有一个能被读取的字节,会返回-1。 while ((hasRead = fis.read(buf)) > 0){ //取出字节,将字节数组转换成字符串数输入 System.out.println(new String(buf,0,hasRead)); } //关闭文件输入流,放在 finally中更安全 fis.close(); }}
使用FileReader 来读取文件本身数据:
/** * Created by 杨Sir on 2017/10/30. */public class FileReaderTest { public static void main(String[] args){ try( //创建字符输入流, JDK 1.7以后,这样写,系统自动关闭流 FileReader fr = new FileReader("D:\\绝对路径\\FileReaderTest.java"); ){ char[] cbuf = new char[32]; //这时需要多次调用read()读取 //保存实际读取的字符数 int hasRead = 0; while((hasRead = fr.read(cbuf)) > 0){ System.out.println(new String(cbuf, 0, hasRead)); } } catch (IOException e) { e.printStackTrace(); } }}
除此之外,InputStream 和 Reader还支持如下几个方法移动指针:
void mark(int readAheadLimit): 在记录指针当前位置记录一个标记。
boolean markSupported() : 判断此流是否支持 mark()操作,即是否支持记录标记。
void reset(): 将此流的记录指针重新定位到上一次记录标记(mark)的位置。
long skip(long n): 记录指针向前移动 n个字符/字节。
我们在来看 OutputStream 和 Writer
他们各自提供了一个用于写入文件的输入流:FileOutputStream 和 FileWriter,他们都是节点流,会直接和指定文件关联。
其实OutputStream 和 Writer 也非常相似, 他们共同提供了如下三个方法:
void write(int c): 将指定的字节或字符输出到输出流中。
void write(byte[]/char[] buf): 将字节数组或字符数组中的数据输出到指定输出流中。
void write(byte[]/char[] buf, int off, int len):将字节数组/字符数组中从off位置开始,长度为len的字节或字符输出到输出流中。
因为字符流可以直接额以字符做操作单位,所以Writer可以用字符串代替字符数组。因此Writer 里还有两个方法:
void write(String str): 将字符串中的字符输出到输出流中。
void wirte(String str , int off ,int len): 将字符串中off开始,长度为len的字符输出到输出流中。
下面举例 利用FileInputStream输入,并使用 FileOutputStream执行输出,实现复制FileOutputStreamTest的功能。
/** * Created by 杨Sir on 2017/10/30. * 利用FileInputStream输入,并使用 FileOutputStream执行输出,实现复制FileOutputStreamTest的功能 */public class FileOutputStreamTest { public static void main(String[] args){ try( //创建字节输入流 FileInputStream fis = new FileInputStream("D:\\绝对路径\\FileOutputStreamTest.java"); //创建字节输出流 FileOutputStream fos = new FileOutputStream("FileOutputStreamTest.txt") ) { byte[] buf = new byte[1024]; int hashead = 0; //循环取数据 while ((hashead = fis.read(buf)) > 0) { //每读取一次,写入一次,读多少,写多少,,可以看到当前路径下多了一个 FileOutputStreamTest.txt文件 fos.write(buf, 0, hashead); } }catch (IOException e){ e.printStackTrace(); } }}
如果希望直接输出字符串内容,使用Writer会更好:
/** * Created by 杨Sir on 2017/10/30. * 当前路径下会输出一个 FileWriterTest.txt 文件。 */public class FileWriterTest { public static void main(String[] args){ try ( //创建字符输出流 FileWriter fw = new FileWriter("FileWriterTest.txt")) { // "\r\n"是windows的换行符,UNIX/Linux/BSD等平台,使用"\n"换行 fw.write("锦瑟 - 李商隐\r\n"); fw.write("锦瑟无端五十弦,一悬疑蛛丝年华。\r\n"); fw.write("庄生晓梦迷蝴蝶,望帝春心托杜鹃。\r\n"); } catch (IOException e) { e.printStackTrace(); } }}
以上介绍了4个访问文件的节点流的用法,4个基类使用优点繁琐。如果希望简化编程,就需要借助处理流了。处理流后面在更新。。。
- Java 的 IO 四大基类详解(上)
- java中的IO详解(上)
- java中的IO详解(上)
- java IO流详解(上)
- Java io详解(-)
- Java四大集合详解
- JAVA IO(二)File类详解
- Java IO系统(上)
- JAVA的 IO流 详解
- 【转】Java的IO详解
- 【转】Java的IO详解
- java IO详解(转)
- java IO详解(二)
- JAVA IO详解(转)
- Java se 四大块之IO
- Java se四大块之线程(上)
- Java四大核心技术思想详解
- java四大线程池详解
- 220. Contains Duplicate III
- 动态调用webservice
- js基础语法
- win10 uwp 萤火虫效果
- 树规 [Heoi2013]Sao
- Java 的 IO 四大基类详解(上)
- Java中的代码块
- 人脸识别(VS2015+opencv3.2的配置)
- Sublime Text 3安装Package Control
- opencv学习——利用轮廓画矩阵、外接圆、拟合曲线
- 算法
- 操作系统笔记:书Page188第50题
- 《每日练习》
- xml从入门到精通之xml文件和java文件的转化