Java深入浅出说流的使用
目录
- 一、File类的使用
- A.常用构造器
- B.路径分隔符
- C.常用方法
- 二、流的分类及其体系
- 输入、输出的标准化过程
- 1.输入过程
- 2.输出过程
- 三、流的详细介绍
- 1.字节流和字符流
- 2.节点流和处理流(重点)
- 3.其他流
- 1.标准的输入、输出流
- 对象流 (重点)
- 对象流的使用
- Person类
- 对象的序列化机制
- 随机存取文件流(了解)
- Java中的NIO
一、File类的使用 1.File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)
2.File了声明在java.io包下
3.File类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法。
并涉及到写入或读取文件内容的操作。入宫需要读取或写入文件内容,必须使用IO流来完成。
4.后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的"终点"。
文章图片
A.常用构造器
文章图片
B.路径分隔符
文章图片
/*1.如何创建File类的实例File(String filePath)File(String parentPath,String,childPath)File(File parentFile,String childPath)2.相对路径:相较于某个路径下,知名的路径。绝对路径:包含盘符在内的未见或文件目录的路径3.路径分隔符windows:\\unix:/*/public void test1() {//构造器1File file1 = new File("hello.txt"); //相对于moduleFile file2 = new File("E:\\zxdym\\IDEA\\code\\JavaSenior\\2021_08\\he.txt"); System.out.println(file1); System.out.println(file2); //构造器2File file3 = new File("E:\\zxdym\\IDEA\\code", "JavaSenior"); System.out.println(file3); //构造器3File file4 = new File(file3, "hi.txt"); System.out.println(file4); }
C.常用方法
【Java深入浅出说流的使用】
文章图片
文章图片
文章图片
public void test2() {File file1 = new File("hello.txt"); File file2 = new File("d:\\io\\hi.txt"); System.out.println(file1.getAbsolutePath()); System.out.println(file1.getPath()); System.out.println(file1.getName()); System.out.println(file1.getParent()); System.out.println(file1.length()); System.out.println(new Date(file1.lastModified())); System.out.println(); System.out.println(file2.getAbsolutePath()); System.out.println(file2.getPath()); System.out.println(file2.getName()); System.out.println(file2.getParent()); System.out.println(file2.length()); System.out.println(file2.lastModified()); }public void test3() {File file = new File("E:\\\\zxdym\\\\IDEA\\\\code\\\\JavaSenior"); String[] list = file.list(); for (String s : list) {System.out.println(s); }System.out.println(); File[] files = file.listFiles(); for (File f : files) {System.out.println(f); }}/*public boolean removeTo(File dest):把文件重命名为指定的文件路径比如:file1.renameTo(file2)为例:要想保证返回true,需要file1在硬盘中是存在的,且file2不能在硬盘中存在。*/@Testpublic void test4() {File file1 = new File("hello.txt"); File file2 = new File("D:\\io\\hi.txt"); boolean renameTo = file1.renameTo(file2); System.out.println(renameTo); } @Testpublic void test5() {File file1 = new File("hello.txt"); System.out.println(file1.isDirectory()); System.out.println(file1.isFile()); System.out.println(file1.exists()); System.out.println(file1.canRead()); System.out.println(file1.canWrite()); System.out.println(file1.isHidden()); } @Testpublic void test6() throws IOException {File file1 = new File("hi.txt"); if (!file1.exists()) {file1.createNewFile(); System.out.println("创建成功"); } else {//文件存在file1.delete(); System.out.println("删除成功"); }}@Testpublic void test7(){//文件目录的创建File file1 = new File("e:\\io\\io1\\io3"); boolean mkdir = file1.mkdir(); if(mkdir){System.out.println("创建成功1"); } File file2 = new File("e:\\io\\io1\\io3"); boolean mkdir1 = file1.mkdirs(); if(mkdir1){System.out.println("创建成功2"); }}
D.注意点
文章图片
二、流的分类及其体系
文章图片
文章图片
文章图片
开发中,用缓冲流,效率比节点流高(蓝色框中的表示重要的、常用的)
输入、输出的标准化过程
1.输入过程 A.创建File类的对象,指明读取的数据的来源。(要求此文件一定要存在)
B.创建相应的输入流,将File类的对象作为参数,传入流的构造器中
C.具体的读入过程:
创建相应的byte[] 或 char[]
D.关闭流资源
说明:程序中出现的异常需要使用try-catch-finally处理。
2.输出过程 A.创建File类的对象,指明写出的数据的来源。(要求此文件一定要存在)
B.创建相应的输出流,将File类的对象作为参数,传入流的构造器中
C.具体的写出过程:
write(char[]/byte[] buffer,0,len)
D.关闭流资源
说明:程序中出现的异常需要使用try-catch-finally处理。
public class FileReaderWriterTest {public static void main(String[] args) {File file = new File("hello.txt"); //相较于前工程System.out.println(file.getAbsolutePath()); File file1 = new File("2021_08\\hello.txt"); System.out.println(file1.getAbsolutePath()); }/*将day09下的hello.txt文件内容读入程序中,并输出到控制台说明点:1.read()的理解,返回读入的一个字符,如果达到文件末尾,返回-12.异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理3.读入的文件一定要存在,否则就会报FileNotFoundException.*/@Testpublic void testFileReader(){FileReader fr = null; try {//1.实例化File类的对象,指明要操作的文件File file = new File("hello.txt"); //相较于当前Module//2.提供具体的流fr = new FileReader(file); //3.数据的读入//read():返回读入的一个字符,如果达到文件末尾,返回-1//方式一://int data = https://www.it610.com/article/fr.read(); //while(data != -1){//System.out.print((char)data); //data = fr.read(); //}//方式二:语法上针对方式一的修改int data; while((data = fr.read()) != -1){System.out.print((char)data); }} catch (IOException e) {e.printStackTrace(); } finally {//4.流的关闭操作try {if(fr != null)fr.close(); } catch (IOException e) {e.printStackTrace(); } finally {}}}@Testpublic void testFileReader1(){FileReader fr = null; try {//1.File类的实例化File file = new File("hello.txt"); //2.FileReader流的实例化fr = new FileReader(file); //3.读入的操作//read(char[] cbuf):返回每次读入cbuf数组中的字符的个数,如果达到文件末尾,返回-1char[] cbuf = new char[5]; int len; while(( len = fr.read(cbuf)) != -1){//方式一://错误的写法//知识点难点:数组元素的覆盖//for(int i = 0; i < cbuf.length; i++){//System.out.print(cbuf[i]); //}//正确的写法//for(int i = 0; i < len; i++){//System.out.print(cbuf[i]); //}//方式二://错误的写法,对应着方式一的错误的写法//String str = new String(cbuf); //System.out.println(str); //正确的写法String str = new String(cbuf, 0, len); System.out.print(str); }} catch (IOException e) {e.printStackTrace(); } finally {if(fr != null){//4.资源的关闭try {fr.close(); } catch (IOException e) {e.printStackTrace(); }}}}/*从内存中写出数据到硬盘的文件里说明:1.输出操作,对应的File可以不存在的,并不会报异常2.File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件File对应的硬盘中的文件如果存在:如果流使用的构造器是:FileWriter(file,false) / FileWriter(file):对原有文件的覆盖如果流使用的构造器是:FileWriter(file,true):不会对原有文件覆盖,而是在原有文件基础上追加内容*/@Testpublic void testFileWriter() {FileWriter fw = null; try {//1.提供File类的对象,指明写出到的文件File file = new File("hello1.txt"); //2.提供FileWriter的对象,用于数据的写出fw = new FileWriter(file,false); //3.写出的操作fw.write("I have a dream!\n"); fw.write("you need to have a dream!"); } catch (IOException e) {e.printStackTrace(); } finally {//4.流资源的关闭if(fw != null){try {fw.close(); } catch (IOException e) {e.printStackTrace(); }}}}@Testpublic void testFileReaderFileWriter(){FileReader fr = null; FileWriter fw = null; try {//1.创建File类的对象,指明读入和写出的文件File srcFile = new File("hello.txt"); File destFile = new File("hello2.txt"); //不能使用字符流来处理图片等字节数据//File srcFile = new File("爱情与友情.jpg"); File destFile = new File("爱情与友情1.jpg"); //2.创建数据入流和输出流的对象fr = new FileReader(srcFile); fw = new FileWriter(destFile); //3.数据的读入和写出操作char[] cbuf = new char[5]; int len; //记录每次读入到cbuf数组中的字符的个数while((len = fr.read(cbuf)) != -1){//每次写出len个字符fw.write(cbuf,0,len); }} catch (IOException e) {e.printStackTrace(); } finally {////4.关闭流资源////方式一://try {//fw.close(); //} catch (IOException e) {//e.printStackTrace(); //}finally {//try {//fr.close(); //} catch (IOException e) {//e.printStackTrace(); //}//}//方式二:try {fw.close(); } catch (IOException e) {e.printStackTrace(); }try {fr.close(); } catch (IOException e) {e.printStackTrace(); }}}}
三、流的详细介绍
1.字节流和字符流
测试FileInputStream和FileOutputStream的使用 public class FileInputOutputStreamTest {//使用字节流FileInputOutputStream处理文本文件,可能出现乱码@Testpublic void testFileInputStream(){FileInputStream fis = null; try {//1.造文件File file = new File("hello.txt"); //2.造流fis = new FileInputStream(file); //3.读数据byte[] buffer = new byte[5]; int len; //记录每次读取的字节的个数while((len = fis.read(buffer)) != -1){String str = new String(buffer, 0, len); System.out.print(str); }} catch (IOException e) {e.printStackTrace(); } finally {//4.关闭资源try {fis.close(); } catch (IOException e) {e.printStackTrace(); }}}/*实现对图片的复制操作*/@Testpublic void testFileInputOutputStream(){FileInputStream fis = null; FileOutputStream fos = null; try {File srcFile = new File("爱情与友情.jpg"); File destFile = new File("爱情与友情2.jpg"); fis = new FileInputStream(srcFile); fos = new FileOutputStream(destFile); //复制的过程byte[] buffer = new byte[5]; int len; while((len = fis.read(buffer)) != -1){fos.write(buffer,0,len); }} catch (IOException e) {e.printStackTrace(); } finally {if(fos != null){try {fos.close(); } catch (IOException e) {e.printStackTrace(); }}if(fis != null){try {fis.close(); } catch (IOException e) {e.printStackTrace(); }}}}//指定路径下文件的复制public void copyFile(String srcPath,String destPath){FileInputStream fis = null; FileOutputStream fos = null; try {File srcFile = new File(srcPath); File destFile = new File(destPath); fis = new FileInputStream(srcFile); fos = new FileOutputStream(destFile); //复制的过程byte[] buffer = new byte[5]; int len; while((len = fis.read(buffer)) != -1){fos.write(buffer,0,len); }} catch (IOException e) {e.printStackTrace(); } finally {if(fos != null){try {fos.close(); } catch (IOException e) {e.printStackTrace(); }}if(fis != null){try {fis.close(); } catch (IOException e) {e.printStackTrace(); }}}}@Testpublic void testCopyFile(){long start = System.currentTimeMillis(); String srcPath = "C:\\Users\\Administrator\\Desktop\\01-视频.avi"; String destPath = "C:\\Users\\Administrator\\Desktop\\02-视频.avi"; copyFile(srcPath,destPath); long end = System.currentTimeMillis(); System.out.println("复制操作花费的时间为:" + (end - start)); }}
结论:
1.对于文本文件(.txt,.java,.c,.cpp),使用字符流处理
2.对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,...),使用字节流处理
2.节点流和处理流(重点)
处理流之一:缓冲流的作用
1.缓冲流:
BufferedInputStream
BufferedOutputStream
BufferedReader
BufferedWriter
2.作用:提高流的读取,写入的速度
提高读写速度的原因:内部提供了一个缓冲区,默认情况是8kb
3.处理流:就是"套接"在已有流的基础上
public class BufferedTest {@Testpublic void BufferedStreamTest(){BufferedInputStream bis = null; BufferedOutputStream bos = null; try {//1.造文件File srcFile = new File("爱情与友情.jpg"); File destFile = new File("爱情与友情3.jpg"); //2.造流//2.1造节点流FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(destFile); //2.2造缓冲流bis = new BufferedInputStream(fis); bos = new BufferedOutputStream(fos); //3.复制的细节:读取、写入byte[] buffer = new byte[10]; int len; while((len = bis.read(buffer)) != -1){bos.write(buffer,0,len); //bos.flush(); //刷新缓冲区}} catch (IOException e) {e.printStackTrace(); } finally {//4.资源关闭//要求:先关闭外层的流,再关闭内层的流if(bos != null){try {bos.close(); } catch (IOException e) {e.printStackTrace(); }}if(bis != null){try {bis.close(); } catch (IOException e) {e.printStackTrace(); }}//说明:关闭外层流的同时,内层流也会自动的进行关闭,关于内层流的关闭,可以省略//fos.close(); //fis.close(); } }@Testpublic void testCopyFileWithBuffered(){long start = System.currentTimeMillis(); String srcPath = "C:\\Users\\Administrator\\Desktop\\01-视频.avi"; String destPath = "C:\\Users\\Administrator\\Desktop\\03-视频.avi"; copyFileWithBuffered(srcPath,destPath); long end = System.currentTimeMillis(); System.out.println("复制操作花费的时间为:" + (end - start)); }//实现文件复制的方法public void copyFileWithBuffered(String srcPath,String destPath) {BufferedInputStream bis = null; BufferedOutputStream bos = null; try {//1.造文件File srcFile = new File(srcPath); File destFile = new File(destPath); //2.造流//2.1造节点流FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(destFile); //2.2造缓冲流bis = new BufferedInputStream(fis); bos = new BufferedOutputStream(fos); //3.复制的细节:读取、写入byte[] buffer = new byte[10]; int len; while ((len = bis.read(buffer)) != -1) {bos.write(buffer, 0, len); }} catch (IOException e) {e.printStackTrace(); } finally {//4.资源关闭//要求:先关闭外层的流,再关闭内层的流if (bos != null) {try {bos.close(); } catch (IOException e) {e.printStackTrace(); }}if (bis != null) {try {bis.close(); } catch (IOException e) {e.printStackTrace(); }}//说明:关闭外层流的同时,内层流也会自动的进行关闭,关于内层流的关闭,可以省略//fos.close(); //fis.close(); }}/*使用BufferedReader和BufferedWriter实现文本文件的复制*/@Testpublic void testBufferedReaderBufferedWriter(){BufferedReader br = null; BufferedWriter bw = null; try {//创建文件和相应的流br = new BufferedReader(new FileReader(new File("dpcp.txt"))); bw = new BufferedWriter(new FileWriter(new File("dpcp1.txt"))); //读写操作//方式一:使用char[]数组//char[] cbuf = new char[1024]; //int len; //while((len = br.read(cbuf)) != -1){//bw.write(cbuf,0,len); //}//方式二:使用StringString data; while((data = https://www.it610.com/article/br.readLine()) != null){//方法一:bw.write(data +"\n"); //data中不包含换行符//方法二:bw.write(data); //data中不包含换行符bw.newLine(); //提供换行的操作}} catch (IOException e) {e.printStackTrace(); } finally {//关闭资源if(bw != null){try {bw.close(); } catch (IOException e) {e.printStackTrace(); }}if(br != null){try {br.close(); } catch (IOException e) {e.printStackTrace(); }}}}}
处理流之二:转换流的使用(重点)
1.转换流:属于字符流
InputStreamReader:将一个字节的输入流转换为字符的输入流
OutputStreamWriter:将一个字符的输出流转换为字节的输出流
文章图片
文章图片
2.作用:提供字节流与字符流之间的转换
3.解码:字节、字节数组 ---> 字符数组、字符串
编码:字符数组、字符串---> 字节、字节数组
说明:编码决定了解码的方式
4.字符集
说明:文件编码的方式(比如:GBK),决定了解析时使用的字符集(也只能是GBK)
public class InputStreamReaderTest {/*此时处理异常的话,仍然应该使用try-catch-finally*/@Testpublic void test1() throws IOException{FileInputStream fis = new FileInputStream("dbcp.txt"); //InputStreamReader isr = new InputStreamReader(fis); //使用系统默认的字符集//参数2指明了字符集,具体使用那个字符集,取决于文件dbcp.txt保存时使用的字符集InputStreamReader isr = new InputStreamReader(fis, "UTF-8"); char[] cbuf = new char[20]; int len; while((len = isr.read(cbuf)) != -1){String str = new String(cbuf,0,len); System.out.print(str); }isr.close(); }/*此时处理异常的话,仍然应该使用try-catch-finally综合使用InputStreamReader和OutputStreamWriter*/@Testpublic void test2() throws Exception{//1.造文件、造流File file1 = new File("dbcp.txt"); File file2 = new File("dbcp_gbk.txt"); FileInputStream fis = new FileInputStream(file1); FileOutputStream fos = new FileOutputStream(file2); InputStreamReader isr = new InputStreamReader(fis, "UTF-8"); OutputStreamWriter osw = new OutputStreamWriter(fos, "gbk"); //2.读写过程char[] cbuf = new char[20]; int len; while((len = isr.read(cbuf)) != -1){osw.write(cbuf,0,len); }//3.关闭资源isr.close(); osw.close(); }}
文章图片
文章图片
3.其他流
1.标准的输入、输出流
1.1System.in:标准的输入流,默认从键盘输入
文章图片
System.out:标准的输入流,默认从控制台输出
1.2System类的setIn() / setOut()方式重新指定输入和输出的流。
修改默认的输入和输出行为:
System类的setIn(InputStream is) / setOut(PrintStream ps)方式重新指定输入和输出的流。
1.3练习:
从键盘输入字符串,要求将读取道德整行字符串转换成大写输出。然后继续进行输入操作。
直至当输入"e"或"exit"时,退出程序
方法一:使用Scanner实现,调用next()返回一个字符串
方法二:使用System.in实现。System.in ---> 转换流 -->BufferedReader的readLine()
public static void main(String[] args) {BufferedReader br = null; try {InputStreamReader isr = new InputStreamReader(System.in); br = new BufferedReader(isr); while(true){System.out.println("请输入字符串:"); String data = https://www.it610.com/article/br.readLine(); //调用此方法读取一行数据if("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)){//避免空指针的写法,之前有System.out.println("程序结束"); break; }String upperCase = data.toUpperCase(); System.out.println(upperCase); }} catch (IOException e) {e.printStackTrace(); } finally {if(br != null){try {br.close(); } catch (IOException e) {e.printStackTrace(); }}}}
文章图片
文章图片
对象流 (重点)
文章图片
对象流的使用
1.ObjectInputStream和ObjectOutputStream
2.作用:用于存储和读取基本数据类型或对象的处理流。
3.要想一个Java对象是可序列化的,需要满足相应的要求。见Person.java
4.序列化机制:(重点!!!!)
对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久的保存在磁盘上,或通过网络将这种
二进制流传输到另一个网络节点,当其他程序获取了这种二进制流,就可以恢复成原来的Java对象
序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去使用ObjectOutputStream实现@Testpublic void testObjectOutputStream(){ObjectOutputStream oos = null; try {oos = new ObjectOutputStream(new FileOutputStream("object.dat")); oos.writeObject(new String("我爱北京天安门")); oos.flush(); //刷新操作oos.writeObject(new Person("王铭",23)); oos.flush(); } catch (IOException e) {e.printStackTrace(); } finally {if(oos != null){try {oos.close(); } catch (IOException e) {e.printStackTrace(); }}}}反序列化:将磁盘文件中的对象还原为内存中的一个Java对象使用ObjectInputStream来实现@Testpublic void testObjectInputStream(){ObjectInputStream ois = null; try {ois = new ObjectInputStream(new FileInputStream("object.dat")); Object obj = ois.readObject(); String str = (String) obj; Person p = ois.readObject(); System.out.println(str); System.out.println(p); }catch(IOException e){e.printStackTrace(); }catch(ClassNotFoundException e){e.printStackTrace(); }finally {if(ois != null){ois.close; }}}
Person类
Person需要满足如下的要求,方可序列化
1.需要实现接口:Serializable
2.当前类提供一个全局常量:serialVersionUID
3.除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的(默认情况下,基本数据类型、String:本身是可序列化的)
补充:ObjectOutputStream 和 ObjectInputStream不能序列化static和transient修饰的成员变量
eg:输出结果:Person{name='null',age=0,id=0,acct=null}
public class Person implements Serializable{public static final long serialVersionUID = 397497937034L; private String name; private int age; @Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}'; }public String getName() {return name; }public void setName(String name) {this.name = name; }public int getAge() {return age; }public void setAge(int age) {this.age = age; }public Person(String name, int age) {this.name = name; this.age = age; }public Person() {}}
对象的序列化机制
文章图片
文章图片
随机存取文件流(了解)
文章图片
文章图片
文章图片
文章图片
RandomAccessFile 1.RandomAccessFile直接继承于java.lang.Object类,实现了DataInput和DataOutput接口 2.RandomAccessFile既可以作为一个输入流,又可以作为一个输出流 3.如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建如果写出到的文件存在,则会对原有文件内容进行覆盖,(默认情况下,从头覆盖) 4.可以通过相关的操作,实现RandomAccessFile"插入"数据的效果 public abstract class RandomAccessFileTest {@Testpublic void test1(){RandomAccessFile raf1 = null; RandomAccessFile raf2 = null; try {raf1 = new RandomAccessFile(new File("爱情与友情.jpg"), "r"); raf2 = new RandomAccessFile(new File("爱情与友情1.jpg"), "rw"); byte[] buffer = new byte[1024]; int len; while((len = raf1.read(buffer)) != -1){raf2.write(buffer,0,len); }} catch (IOException e) {e.printStackTrace(); } finally {if(raf1 != null){try {raf1.close(); } catch (IOException e) {e.printStackTrace(); }}if(raf2 != null){try {raf2.close(); } catch (IOException e) {e.printStackTrace(); }}}}@Testpublic void test2()throws IOException{RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw"); raf1.seek(3); //将指针调到角标为3的位置raf1.write("xyz".getBytes()); //raf1.close(); }使用RandomAccessFile实现数据的插入效果@Testpublic void test3() throws IOException{RandomAccessFile raf1 = new RandomAccessFile("hello.txt", "rw"); raf1.seek(3); //将指针调到角标为3的位置//保存指针3后面的所有数据到StringBuilder中StringBuilder builder = new StringBuilder((int) new File("hello.txt".length())); byte[] buffer = new byte[20]; int len; while((len = raf1.read(buffer)) != -1){builder.append(new String(buffer,0,len)); }//调回指针,写入"xyz"raf1.seek(3); raf1.write("xyz".getBytes()); //将StringBuilder中的数据写入到文件中raf1.write(builder.toString().getBytes()); raf1.close(); }}
Java中的NIO
文章图片
文章图片
文章图片
到此这篇关于Java深入浅出说流的使用的文章就介绍到这了,更多相关Java流内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 尽力
- 一个人的碎碎念
- 时间老了
- 午门传说
- 我们重新了解付费。
- 说的真好
- 事件代理
- “不完美,才美”01(190410)