本文共 6014 字,大约阅读时间需要 20 分钟。
windows路径可以用\或/,linux路径用/,为跨平台一律使用/。
File即可以指文件,也可以指目录(文件夹)。File类常用的方法
String getName() //获取文件|文件夹名,文件名包括后缀boolean exists() boolean isFile() boolean isDirectory()long length() //文件|文件夹的大小,字节long lastModified() //最后修改时间,时间戳String[] list() //返回所有的子文件、子文件夹,String[]File[] listFiles() //返回所有的子文件、子文件夹,File[]File file;// 以上2个方法均可带FilenameFilter类型的参数,对结果进行过滤,只返回符合条件的文件夹、文件// FilenameFilter是一个函数式接口,只需实现 accept(File dir, String filename) 方法String[] arr = file.list((dir, filename) -> { //dir是file对应的文件夹,filename是其下的子文件夹名、子文件名 return filename.endsWith(".txt"); //返回true才保留此filename}); boolean createNewFile() //新建文件,如果前面的路径不存在,会自动创建boolean mkdir() //新建文件夹,如果前面的路径不存在,不做任何操作boolean mkdirs() //新建文件夹,如果前面的路径不存在,会自动创建boolean delete() //删除文件|文件夹
支持随机访问,可在文件中的任意位置读写数据,常用于实现断点传输、断点下载。
按流的方向分
按操作的数据单元分
按流的角色分
处理流是一种典型的装饰器设计模式,使用处理流包装不同的节点流,可以消除不同节点流的差异,以同样的操作方式来操作。
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
---|---|---|---|---|
抽象基类 | InputStream | OutputStream | Reader | Writer |
操作文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
操作数组 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
操作字符串 | StringReader | StringWriter | ||
缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
转换流 | InputStreamReader | OutputStreamWriter | ||
对象流(用于序列化) | ObjectInputStream | ObjectOutputStream | ||
打印流(输出功能十分强大) | PrintStream(也可直接操作字符) | PrintWriter | ||
音频输入、输出 | AudioInputStream | AudioOutputStream | ||
加密、解密 | CipherInputStream | CipherOutputStream | ||
压缩、解压 | ZipInputStream | ZipOutputStream |
FileInputStream fis=new FileInputStream("./1.txt");byte[] buff=new byte[1024];int length=0;while ((length=fis.read(buff))!=-1){ //已读完返回-1 System.out.println(new String(buff,0,length)); //读写文件使用数组时都应该使用length,不然最后一次数组读写时会读写到数组中空的部分}fis.close();
FileReader fr=new FileReader("./1.txt");char[] buff=new char[1024];int length=0;while ((length=fr.read(buff))!=-1){ System.out.println(new String(buff,0,length));}fr.close();
//默认是覆盖FileOutputStream fos=new FileOutputStream("./2.txt");fos.write("hello\n".getBytes());fos.close();//可指定是否是追加模式,true——是追加模式,false——不是追加模式(即覆盖)fos=new FileOutputStream("./2.txt",true);fos.write("hello\n".getBytes());fos.close();
//默认是覆盖FileWriter fw=new FileWriter("./2.txt");fw.write("hello\n");fw.close();//追加fw=new FileWriter("./2.txt",true);fw.write("world!");fw.close();
文件可以分为文本文件、二进制文件,从底层来看,所有的文件都基于字节,都是二进制文件。
字节流可以操作所有的文件,字符流只能操作文本文件,字符流操作文本文件更简单,一般使用字符流操作文本文件,使用字节流操作二进制文件。
内置的流对象
FileInputStream、FileWriter、FileOutputStream、FileWriter都是直接操作IO节点(文件),是节点流,包装流用来包装一个已存在的流,不直接操作IO节点,消除了节点流之间的差异,可以用同样的方式操作不同的节点流。
FileOutputStream fos=new FileOutputStream("./1.txt");//以一个已存在的流对象作为参数PrintStream ps=new PrintStream(fos);//可以字节为单位操作ps.write("你好!".getBytes());//可以字符为单位操作ps.print("很高兴认识你!");//println()输出后直接换行,不用我们在写\n,更加简便ps.println("xxxxxxxxxx");//可输出各种类型的数据ps.write(12);ps.print(12);ps.print(12.34);//关闭处理流时,会自动关闭其包装的节点流,代码更简洁。ps.close();
PrintStream使用简单、输出功能十分强大。
之前我们手动创建数组,用byte[ ]、char[ ]做缓冲区,提高读写效率。
java提供了缓冲流,效果相同,但自带缓冲区(数组),不用我们手动创建、操作数组,更加简便
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("./1.txt"));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("./2.txt"));//文件复制int i;while ((i = bis.read()) != -1){ //i是读取的内容的码值 bos.write(i); //将读取的数据写到输出流,会自动将码值转换为相应的内容}//关闭包装流,会自动关闭对应的节点流bis.close();bos.close();
java提供了2个转化流,可以将字节流转换为字符流
// InputStreamReaderInputStreamReader isr=new InputStreamReader(InputStream is);// OutputStreamWriterOutputStreamWriter isr=new OutputStreamWriter(OutputStream os);
字符流本身操作就很方便,没有提供将字符流转换为字节流的类
序列化(Serialize):将内存中的对象转换为二进制数据(字节序列),通过输出流存储到文件中,或传输到网络节点上。
反序列化(Deserialize):将输入流中的二进制数据恢复为内存中的对象。
实现序列化的2种方式
序列化
String filePath = "/xxx/xxx.txt";User user1 = new User(1, "张三", 20);User user2 = new User(2, "李四", 20);User user3 = new User(3, "王五", 20);//获取输出流,参数是输出流OSObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));//输出到文件|网络节点。writeObject()一次只能写出一个对象oos.writeObject(user1);oos.writeObject(user2);oos.writeObject(user3);
反序列化
String filePath = "/xxx/xxx.txt";//获取输入流,参数是输入流ISObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));//返回的是Object,需要强转//readObject()只能读一个对象,读取一个对象后,指针自动后移,指向下一个对象,读的顺序和写的顺序一一对应User user1 = (User) ois.readObject();User user2 = (User) ois.readObject();User user3 = (User) ois.readObject();
注意点
public class Student extends User implements Serializable { private Float score; //不想序列化的成员变量,比如密码等私密字段,使用transient修饰 private transient String password; //如果持有自定义类的引用,该类要是可序列化的,当前类才能序列化 private Teacher teacher; //.......}
如果当前类实现了序列化接口,且有父类,当前类要是可序列化的,还需要保证以下任意一点
浅拷贝
深拷贝
深拷贝的常见实现方式
第一、二种方式,如果存在引用类型的字段内部多级嵌套引用类型,则很麻烦,推荐使用第三种方式,简单。
使用序列化、反序列化实现深拷贝
@Overridepublic User clone() { User user = null; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); //强转为目标类型 user = (User) ois.readObject(); } catch (IOException | ClassNotFoundException e) { System.out.println("深拷贝失败!"); e.printStackTrace(); } return user;}
序列化时,会拷贝对象到IO流中,这个拷贝是深拷贝,所以直接从IO流中读取对象即可。
转载地址:http://wwhlb.baihongyu.com/