做任务 网站,品牌策划文案,优秀的移动端网站,企业门户网站实现本章内容
一 、File概念
File可以代表一个目录或者一个文件#xff0c;并不能代表文件的内容 文件和流的区别#xff1a;File关注的是文件本身的特征#xff0c;如名称、路径、修改时间、大小。 流关注的是文件的内容。
二、File基本的操作 常见构造方法 | File(String p…本章内容
一 、File概念
File可以代表一个目录或者一个文件并不能代表文件的内容 文件和流的区别File关注的是文件本身的特征如名称、路径、修改时间、大小。 流关注的是文件的内容。
二、File基本的操作 常见构造方法 | File(String pathname) | 建立一个以pathname为路径的File对象 pathname可以是相对路径也可以是绝对路径。 | | ———————————————— | —————————————————————————————— | | File(String parent,String child) | 建立一个以parent加上child为路径的File对象 | | File(File parent,String child) | 建立一个以parent加上child为路径的File对象 | 注意文件的路径如果考虑跨平台就使用File.seperator 相对路径javase程序中相对参照点为项目目录 src/test.项目目录下的src/test 绝对路径e:/test 创建文件操作 mkdir:创建单层目录 dir1/dir2:必须保证dir1是存在的才能成功创建dir2 mkdirs创建层级目录 dir1/dir2如果dir1不存在会先创建dir1,再创建dir2 createNewFile:创建文件 dir1/a :必须保证dir1是存在的否则会报系统找不到指定的路径的异常 文件的常用读操作文件名称、文件名称 exists() //文件或者目录是否存在 isFile() //是否是文件 isDirectory() //是否是目录 getName() //取文件或者目录的名字 getPath() //取文件或者目录的路径 getAbsolutePath() //取文件绝对路径 lastModified() //最后修改日期 length() //文件或者目录的字节大小 list()//获得当前File对象所表示目录下的文件和目录名称返回String[]类型的数据。 listFiles()//获得当前File对象所表示目录下的文件和目录返回File[]类型的数据。 代码实例 修改文件名称 注意修改的新文件名需要是不存在的 ,如果修改前后的目录一致那就是重命名的效果如果修改前后目录不一致相当于会删除旧目录中的文件以新的名称出现在新目录中 // File file new File(baseDir,11.txt);
// file.renameTo(new File(baseDir,bbb/111.txt)); 删除文件 File file new File(baseDir,2.txt); file.delete(); 删除文件夹 递归 1、自己调用自己 2、必须要一个条件 private static void myDelete(File dir) {// TODO Auto-generated method stubif(dir.isDirectory()) {File[] listFiles dir.listFiles();for (File file : listFiles) {if(file.isDirectory()) {myDelete(file);}file.delete();}dir.delete();}}
得有一个明确的递归出口(什么情况下不递归了) 递归算法代码简洁但是效率比较低 1到n的累加和执行过程 | n1 | 0x01 return 1 | fun(1) 1 | | —— | ———————- | ———————————- | | n2 | 0x02 2fun(1) | fun(2) 2fun(1)213 | | n3 | 0x02 3fun(2) | fun(3) 3fun(2)336 | | n4 | 0x02 4fun(3) | fun(4)4fun(3)4610 | | n5 | 0x02: 5fun(4) | fun(5)5fun(4)51015 | | 栈底 | | | 入栈记录信息 出栈根据入栈记录的信息计算结果 fun(1) fun(2) ….. fun(5) public static int fun(int n){if(n1){return 1; //0x01}else{return nfun(n-1); //0x02}}
public static void deleteFile(File f){ if(!f.exists()){ return; } //如果是一个文件 if(f.isFile()){ f.delete();//删除文件 System.out.println(删除文件f.getName()); } //如果是一个目录 if(f.isDirectory()){File fs[]f.listFiles();//满足这个条件不是空目录if(fs.length0){for(File subFile:fs){deleteFile(subFile);}}//删除空目录 f.delete();System.out.println(删除目录f.getName());}
}
三、流的概念
File类关心的是磁盘上存储的文件位置和名称等而流是指程序运行中的数据通信信道当然流类所关心的是文件的内容。
四、流的分类
根据流向分为输入流输出流
根据传输单位:字节流字符流
根据是否和数据源可以直接交互:节点流处理流
节点流可以和数据源直接交互FileInputStream,FileOutPutStream,FileWriter,FileReader
处理流需要连接嵌套其它的流使用,BufferedReader,BufferedWriter
五、流的四个根类 InputStream字节输入流 FileInputStream:节点流字节输入流按照字节为单位读文件文件复制 ObjectInputStream处理流对象输入流需要嵌套一个字节输入流进行使用如FileInputStream反序列化 OutputStream字节输出流 FileOutputStream节点流字节输出流按照字节为单位写文件复制 ObjectOutPutStream处理流对象输出流需要嵌套一个字节输出流如FileOutputStream进行使用序列化 Reader字符输入流 FileReader节点流针对文件的字符输入流以字符为单位读文件存在乱码问题不能直接按行进行读 BufferedReader处理流带缓冲区的字符输入流以行为单位读文件 readLine:返回值为null表示读取结束 InputStreamReader处理流转换流可以将字节流转换为字符流,需要嵌套节点流使用读文件的指定字符集编码解决乱码问题 Writer FileWriter节点流针对文件的字符输出流以字符为单位写文件存在乱码问题不能直接按行写 BufferedWriter 处理流带缓冲区的字符输出流按照行写字符newLine OutPutStreamWriter处理流转换流可以将字节流转换为字符流需要嵌套节点流使用写文件的时候指定字符集编码解决乱码问题 六、字节流 FileInputStream 常用api FileInputStream是InputStream的子类。 FileInputStream是读取文件的字节输入流。 FileInputStream常用的构造方法 FileInputStream(File file) FileInputStream(String filename) FileInputStream覆盖实现了父类如下方法 int available() void close() 字节输入流的代码结构
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
public class StreamDemo {
public static void main(String[] args) throws IOException {//字节流//1、建立文件源数据源的一种File file new File(src/1.txt);//2、建立流链接文件源FileInputStream input new FileInputStream(file);//3、读取数据int read input.read();byte[] bs new byte[1024];int len input.read(bs);int read2 input.read(bs, 2, 5);//使用数据//4、关闭流input.close();}
}
int read():一次读取1个字节返回值表示读取的一个字节的数据一个字节的数据不一定表示一个字符的编码返回值为-1表示读取结束 import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class StreamDemo {
public static void main(String[] args) {//字节流//public abstract class InputStreamFile file new File(src/1.txt);try {//如果是输入流文件必须存在FileInputStream fileInputStream new FileInputStream(file);int n;//read()读取流中的数据while((nfileInputStream.read())!-1) {System.out.println(n);}//关闭流fileInputStream.close();} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}
}
}
int read(byte[ ] b)将文件中读到的数据放到数组中返回值为读取到的字节长度返回值为-1表示读取结束
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
public class StreamDemo {
public static void main(String[] args) {//字节流//public abstract class InputStreamFile file new File(src/1.txt);try {//如果是输入流文件必须存在FileInputStream fileInputStream new FileInputStream(file);byte[] bs new byte[1024];//int read(byte b[]) 将文件中的所有数据读到字节数组中bs//返回值是读取了多少个字节int len fileInputStream.read(bs);
// System.out.println(Arrays.toString(bs));
// System.out.println(len);String str new String(bs);System.out.println(str.trim());//关闭流fileInputStream.close();} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}
}
}
int read(byte[] b,int off,int len)将文件中读到的数据放到数组中的指定位置指定长度返回值为读取到的字节长度返回值为-1表示读取结束
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;public class StreamDemo {public static void main(String[] args) {//字节流//public abstract class InputStreamFile file new File(src/1.txt);try {//如果是输入流文件必须存在FileInputStream fileInputStream new FileInputStream(file);// int n;
// //read()读取流中的数据每次读取一个字节
// while((nfileInputStream.read())!-1) {
// System.out.println(n);
// }byte[] bs new byte[1024];//int read(byte b[]) 将文件中的所有数据读到字节数组中bs//返回值是读取了多少个字节//第一个参数bs存了读取的数据//第二个参数1设置了bs数组从下标1的位置开始存//第三个参数3设置了从文件中读取几个字节int len fileInputStream.read(bs,1,3);System.out.println(Arrays.toString(bs));System.out.println(len);String str new String(bs);System.out.println(str);//关闭流fileInputStream.close();} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}注意read和int read(byte[ ] b)方法返回值代表的意义 FileOutputStream FileOutputStream是OutputStream的子类 FileOutputStream是写入文件的字节输出流 FileOutputStream常用的构造方法 FileOutputStream(File file) FileOutputStream(String filename) FileOutputStream(File file,boolean append) FileOutputStream(String filename,boolean append) FileOutputStream覆盖实现了父类如下方法 void close() void flush() void write(int b) 写入一个字节的数据参数就是要写入的数据的编码 void write(byte[] b) 将数组中的数据写到文件中数组中存放的是字符的编码 void write(byte[] b,int off,int len将数组指定位置指定长度的数据写入的文件中
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;public class OutputStreamDemo {public static void main(String[] args) throws IOException {//FileOutputStream//按照单位字节流//按照方向输出流//按照是否跟源进行关联节点流//1、声明文件源File file new File(src/output.txt);//2、创建字节输出流FileOutputStream fos new FileOutputStream(file);//3、写出数据String str abcdefg;
// for(int i0;istr.length();i) {
// fos.write(str.charAt(i));
// }fos.write(str.getBytes(), 1, 3);//4、关闭流fos.close();}}文件复制
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;public class CopyDemo {public static void main(String[] args) throws IOException {//文件复制File sourceFile new File(G:\\video\\20220530-1-File概念.mp4);File targetFile new File(f:\\64\\1.mp4);FileInputStream input new FileInputStream(sourceFile);FileOutputStream output new FileOutputStream(targetFile);//缓存可以减少io次数可以大大的提升速度byte[] bs new byte[1024*8];int len;while((leninput.read(bs))!-1) {output.write(bs);bs new byte[1024*8];}input.close();output.close();sourceFile.delete();}}七、字符流
字符流适合读写文本字符按照字符读取不能直接按照行读取 FileReader 常用API: int read() 一次读一个字符返回值是读到的一个字符的编码-1表示读取结束 int read(char[] cbuf) 返回值表示读取到字符的个数参数表示存放读取到的数据的数组 int read(char[] cbuf,int off,int len)返回值表示读取到字符的个数参数表示存放读取到的数据的数组 void close() FileWriter 常用API: void write(int ch) :写入单个字符到调用的输出流。 void write(String str) :写入str到输出流。 void write(String str, int off, int len),写入字符串的某一部分。 void write(char[] cbuf) void write(char[] cbuf,int off,int len):写入字符数组的某一部分。 void flush() :清空输出缓冲区。 void close() 关闭输出流。 import java.io.File;
import java.io.FileReader;
import java.io.IOException;public class CharIODemo {public static void main(String[] args) throws IOException {//Reader 字符输入流的父类//FileReader 文件字符输入流FileReader fr new FileReader(new File(src/1.txt));int n;while((nfr.read())!-1) {System.out.println((char)n);}char[] cs new char[1024];while(fr.read(cs,1,3)!-1) {System.out.println(new String(cs).trim());cs new char[1024];}fr.close();//FileWriter 文件字符输出流// FileWriter fw new FileWriter(new File(src/1.txt));fw.write(你吃了么?.toCharArray());fw.write(25105);fw.write((int)我);
// //参数为Stringfw.write(人情味儿发我放散阀);
// fw.close();}}八、嵌套流
流对象被其他处理流的多次连接称为流的嵌套。
直接与数据源相连接的流是节点流
处理流连接节点流提供附加性能
处理流可以被其它处理流继续连接以获取需要的其它性能。
处理流不可以与节点数据源直接连接 九、缓冲流
默认带了8192个字符的缓冲区是为了提高性能减少频繁和硬盘进行io的次数
BufferedReader:处理流字符输入流是Reader的子类提供了readLine方法很实用 import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;public class BufferedReaderDemo {public static void main(String[] args) throws IOException {// BufferedReader//生成数据源File sourceFile new File(src/1.txt);//生成节点流FileReader fr new FileReader(sourceFile);//生成处理流 缓冲流BufferedReader br new BufferedReader(fr);//boolean ready()返回true则可以读while(br.ready()) {//String readLine()可以读出文件中的一行内容如果没有则返回nullSystem.out.println(br.readLine());}br.close();}}获得所有学生并返回集合 import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;public class StuDemo {public static void main(String[] args) throws IOException {//文件中读取内容先封装成学生对象再封装到集合中ListStu stuList new ArrayListStu();BufferedReader br new BufferedReader(new FileReader(new File(src/stu.txt)));while(br.ready()) {//1,张三,18String stuStr br.readLine();//{1,张三,18}String[] arr stuStr.split(,);Stu stu new Stu(Integer.parseInt(arr[0]),arr[1],Integer.parseInt(arr[2]));stuList.add(stu);}br.close();for (Stu stu : stuList) {System.out.println(stu);}}}BufferedWriter:处理流字符输出流是Writer的子类提供了newLine() write(str)方法
写入一个学生 import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;public class BufferedWriterDemo {public static void main(String[] args) throws IOException {//BufferedWriterFile file new File(src/stu.txt);//第二个参数为是否追加true为追加写false为覆盖写FileWriter fw new FileWriter(file,true);BufferedWriter bw new BufferedWriter(fw);Stu stu new Stu(5,田七,23);String str stu.getSid(),stu.getSname(),stu.getSage();bw.write(str);bw.newLine();bw.close();}}十、序列化 对象流 对象输入流ObjectInputStream ObjectInputStream innewObjectInputStream(输入流对象); 相应的方法in.readObject(); 对象输出流ObjectOutputStream ObjectOutputStream outnew ObjectOutputStream(输出流对象); 相应的方法out.writeObject(Object obj); 序列化 序列化就是将对象的内容分解成字节流以便存储在文件中或在网络上传输。 属性的要求非transient 非静态 是可序列化类型Serializable 反序列化就是打开并读取字节流且从该流中恢复该对象 没有执行过反序列化的类型对应的代码块及构造方法 能够序列化的对象必须是Serializable类型对应的类型必须实现Serializable接口 序列化类型中一般会要求提供一个serialVersionUID作用是保证读反序列化和写序列化的过程中类型版本的一致性。如 写的时候版本id为1 那么读的时候版本id也必须是1才能成功 public static void write1() throws IOException{ //处理流 ObjectOutputStream writernew ObjectOutputStream(new FileOutputStream(new File(src/data))); for (int i 0; i 10; i) { Goods goodsnew Goods(00i, 商品i, i10.1f); writer.writeObject(goods); } writer.flush(); writer.close(); }
public static void read1() throws IOException, ClassNotFoundException{ //处理流 ObjectInputStream readernew ObjectInputStream(new FileInputStream(new File(src/data))); while(true){ try { Object objreader.readObject(); System.out.println(obj); } catch (EOFException e) {//EOFException:表示文件读取到末尾了 // TODO Auto-generated catch block System.out.println(读取结束); break; }}reader.close();
} 注意使用EOFException判断文件是否读取到末尾 问题描述 用类ObjectOutputStream向文件写读对象时碰到一个问题新建一个文件用输出流ObjectOutputStream向文件连续写几个对象关闭输出流然 后读取这些对象都可以读出这时在向该文件增加对象新写的对象就读不出了
问题出现的原因 ObjectOutputStream建立后第一次写入一个对象时 会在对象数据前写入一些标志的数据“AC ED 00 05”用二进制方式查看打开应该是流相关的信息。当你关闭 ObjectOutputStream 后再重新打开往文件里面写对象时append方式就会再一次把“AC ED 00 05”写入文件而这些信息并不是你写入对象的数据所以当你用ObjectInputStream来读取对象时流会将除第一个“AC ED 00 05”以外的数据当作各个对象的数据造成无法解析所以读取时有一个java.io.StreamCorruptedException出现。 这个可以通过编辑Info.dat来验证只要将“AC ED 00 05”删除第一个“AC ED 00 05”保留就可以正常读出后来加入的对象。 给出一个比较笨的解决方法 在以后要添加新的对象到Info.dat时将里面原有的对象读出放入ArrayList中清空文件再将对象集一次写入。
尝试解决办法:
那个“AC ED 00 05”是 ObjectOutputStream.writeSystemHeader()写进去的你可以继承ObjectOutputStream类覆盖这个方法。 在你自己的writeSystemHeader()里判断是不是第一次写入一个文件如果是向一个文件大小不为零的文件追加的话就调用 super.reset(),如果是第一次写这个文件不是追加就调用super.writeSystemHeader()
/** * 此类继承ObjectOutputStream重写writeStreamHeader()方法,以实现追加写入时去掉头部信息 */
public static class MyObjectOutputStream extends ObjectOutputStream { private static File f; // writeStreamHeader()方法是在ObjectOutputStream的构造方法里调用的 // 由于覆盖后的writeStreamHeader()方法用到了f。如果直接用此构造方法创建 // 一个MyObjectOutputStream对象那么writeStreamHeader()中的f是空指针 // 因为f还没有初始化。所以这里采用单态模式 private MyObjectOutputStream(OutputStream out, File f) throws IOException, SecurityException { super(out); } // 返回一个MyObjectOutputStream对象这里保证了new MyObjectOutputStream(out, f) // 之前f已经指向一个File对象 public static MyObjectOutputStream newInstance(File file, OutputStream out) throws IOException { f file;// 本方法最重要的地方构建文件对象两个引用指向同一个文件对象 return new MyObjectOutputStream(out, f); } Override protected void writeStreamHeader() throws IOException { // 文件不存在或文件为空,此时是第一次写入文件所以要把头部信息写入。 if (!f.exists() || (f.exists() f.length() 0)) { super.writeStreamHeader(); } else { // 不需要做任何事情 } }
}