首页 > 编程语言 >【Java】韩顺平Java学习笔记 第19章 IO流

【Java】韩顺平Java学习笔记 第19章 IO流

时间:2024-07-29 21:55:43浏览次数:12  
标签:文件 Java 字节 19 write new 序列化 节点 顺平

文章目录

文件概述

  • 保存数据的地方
  • 文件流:文件在程序中是以流的形式操作的
  • 输入流:数据从数据源(文件)到程序(内存)的路径,输出流相反

常用的文件操作

创建文件

  • new File(String pathname) 文件的路径
  • new File(File Parent,String child ) 父目录文件+子路径(文件名)
  • new File(String parent, String child)父目录+子路径
  • 上面是创建文件对象,使用创建方法才能真正创建文件:createNewFile() [需要异常处理]

获取文件信息

  • getName 文件名
  • getAbsolutePath 绝对路径
  • getParent 文件父级目录
  • length 文件大小(字节)
  • exist
  • isFile
  • isDirectory 文件是不是一个目录(文件夹)

目录的操作和文件删除

  • delete (返回boolean 是否删除成功)
  • 在Java中,目录也被当成文件
  • mkdir 创建一级目录**(注意创建文件夹的方法和创建文件不同!)**
  • mkdirs 创建多级目录

流的分类

  • 操作数据单位不同:字节流(8 bit,操作二进制文件时无损操作),字符流(操作文本文件效率更高)

  • 数据流的流向不同:输入流,输出流

  • 流的角色不同:节点流,处理流/包装流

  • 字节输入流:InputStream

    字节输出流:OutputStream

    字符输入流:Reader

    字符输出流:Writer

    上面四个都是抽象类

  • 流和文件的关系:流是文件/程序之间传递信息的介质

各抽象类常用子类对象

FileInputStream

  • read 一个个字节读,返回-1到达文件末尾,注意一个汉字有三个字节
  • 优化减少读取的次数:read(byte[ ] b) 一次最多读取b.length字节的数据到字节数组,返回实际读取的字节数,返回-1说明读取完毕
  • close 关闭文件

FileOutputStream

  • write 写入一个字节

  • String 的 getBytes 可以将字符串转换为字符数组,可以配合write写入字符串

  • write(byte[ ] b)

  • write(byte[ ] b,index1,index2) index为读取字节的起点和终点

  • new 的创建方式,当写入内容时,会覆盖原来的内容

  • new FileOutputStream(filePath,true)的创建方式,写入内容时,在原来的文本后追加

    true 传给参数 append

FileReader

  • 按照字符来操作io,汉字不会乱码
  • new FileReader(File/String,(true)) 可选true,追加模式,需要处理异常
  • 读取方式基本和FileInputStream相同
  • read
  • read(char[ ])
  • new String (char[ ]) 将char转换成String
  • new String(char[ ],off,len)
  • close

FileWriter

  • new FileWriter(File/String,(true)) 可选true,追加模式
  • 注:写完之后必须关闭流(close)或者刷新(flush),才能真正写到文件中(看源码)
  • write(int)
  • write(char[ ])
  • write(char[ ],off,len)
  • write(string)
  • write(string,off,len)(注:off为写入的起始位置)

节点流和处理流

概念

  • 节点流:从某一特定数据源读写数据,如FileReader、FileWriter,但限制较多,功能不强大

  • 处理流(包装流):对节点流进行包装,“连接”已存在的流(节点流或处理流),如BufferedReader、BufferedWriter

    BufferedReader 里面有一个 Read 类型的对象,代表其以后可以实现 Read 的各子类如FileReader、CharReader、StringReader等,使其能够处理各种数据,功能更强大

    使用了修饰器模式

  • 区别和联系

    • 节点流是底层流,直接与数据源相连
    • 处理流包装节点流,通过一个节点流,传入不同的节点流,来统一处理文件的流(都使用处理流),即想处理字符串就把处理字符串的节点流(如StringReader)传入处理流(BufferedReader),想处理数组就把处理数组的节点流(ByteArrayInputStream)传入处理流(BufferedReader),否则每种节点流还需单独创建一个对象。并且还可以拓展输入输出的方式
    • 处理流不直接于数据源相连,而是调用了节点流的方法**(多态和动态绑定)**
  • 处理流优点

    • 提高性能:以增加缓冲的方式来提高输入输出的效率
    • 操作便捷:可能提供一系列便捷的方法来一次输入输出大批量的数据,使用更加灵活方便
  • 要知道什么情况下用什么流!

BufferedReader

  • ​ 和 BufferedWriter 一样是字符流,尽量操作文本文件,不操作二进制文件(图片、音乐等),否则可能造成文件损坏
  • 关闭时关闭外层流即可,即关闭BufferedReader即可,不用关闭内层的节点流(如FileReader),因为关闭外层流的close方法里面调用了节点流的close方法
  • readline 按行读取,效率高,当返回 null 时,读取完毕(看手册),不带换行(用newline手动换行)

BufferedWriter

  • newLine 插入一个和系统相关的换行(不同系统换行不同,因此不建议用\n换行符)
  • 如果要追加,在传入节点流(FileWriter)时传入true,即new BufferedWriter(new FileWriter( path, true))

BufferedInputStream & BufferedOutputStream

  • 字节流,可以操作二进制文件也可以操作文本文件
  • 操作与之前的几个类类似

对象流:ObjectInputStream & ObjectOutputStream

  • 需求:保存数据时同时保存其数据类型(序列化,即把对象保存为文件。从文件恢复为对象称为反序列化

  • 必须让某个类是 可序列化的,有两个方式:

    • 实现 Serializable 接口(推荐,标记接口,没有任何方法)
    • 实现 Externalizable 接口
  • ObjectOutputStream 提供 序列化功能

  • ObjectInputStream 提供 反序列化功能

  • 序列化后,保存的文件格式,是按照其实际格式保存

  • 包装类(如 Integer、Double)和 String 都实现了 Serializable 接口

  • 各种方法与之前的类相似

    需要注意读写文件时需要加上数据类型,如:writeInt、writeDouble、readBoolean、readChar

  • 读取(反序列化)的顺序需要和保存数据(序列化)的顺序一致

  • 需要将自定义数据类型(类)的定义拷贝(或导包)到可以引用的位置(注意该类不要用 private 修饰),这样调用过后才能直接用这个自定义数据类型

  • 如果要调用自定义数据类型的方法,需要向下转型,因为从文件调进来的是Object类型

  • 序列化的类中建议添加 SerialVersionUID (序列版本号),提高序列化兼容性

  • static 和 transient(标记这个变量不应序列化) 修饰的成员不会被序列化

    • transient 使用场景
      • 安全:密码、安全令牌等不应该持久化或通过网络传输
      • 性能:大对象或不重要的对象成员没必要序列化
      • 逻辑需求:某对象只可能对特定上下文有意义,无需序列化
    • 注意事项
      • transient 只能用于变量,不能用于方法和类
      • 局部变量(方法内变量)不能用 transien 修饰,因为局部变量本来就不会被序列化
  • 序列化对象时,要求里面属性的类型(如另一个类的对象)也需要实现序列化接口,即使其被 transient 修饰,不会被序列化,也要实现这个接口

  • 序列化具有可继承性,如某类实现了序列化,则其子类默认实现序列化

  • 注意每次 new 的时候都会调用writeStreamHeader()方法写入4个字节的StreamHeader(看源码),标记这个是对象处理流,可能导致的错误:如果在接收方每次都是new一个新的ObjectInputStream 来接收,而发送方只 new 过一个 ObjectOutputStream,之后每次都是用new过的 ObjectOutputStream对象来发送东西,这样就会导致之后并没有添加头部。而接受方每次都是新的 new,则每次接收都要检测头部,当发送方没有提供头部时,接收方就把内容当做了头部,导致出错。解决方法之一是每次使用 ObjectOutputStream 时都重新 new 一遍

标准输入输出流:System.in & System.out

  • 标准输入(键盘):System.in,InputStream的流对象(编译类型),运行类型是BufferedInputStream

  • 标准输出(显示器):System.out,编译类型和运行类型都是PrintStream,是PrintStream类的一个对象

  • 不需要显式关闭

    • 它们与程序生命周期有关,程序开始运行时由操作系统自动打开,程序终止时也由操作系统自动关闭,无需用户手动操作
    • 标准流通过JVM管理
    • 方便使用
    • 避免以后需要调用时抛出异常
  • System.setOut(new PrintStream(filePath)) 修改标准输出流的打印位置,打印到文件

    filePathSystem.out 代替,则打印到屏幕)

转换流:InputStreamReader & OutputStreamWriter

  • InputStreamReader:将字节流转换成字符流输入到程序,并且根据指定的编码方式转换为字符
  • OutputStreamWriter:将字符流转换成字节流输出到文件,并且根据指定的编码方式转换为字节(如果不用转换流,Java会用默认编码转换为字节)
  • 默认情况下,读取文件是按照 utf-8 编码,如果文件不是 utf-8 编码,则可能出现乱码。根本问题:没有指定编码方式
  • 转换流可以完成字节流和字符流的转换,并且转换流可以指定编码类型
  • InputStreamReader 是 Reader 的子类,可以将 InputStream(字节输入流顶级父类) 转换为 Reader(字符输入流顶级父类)
  • OutputStreamWriter 是 Writer 的子类,可以将 OutputStream 转换为 Writer
  • 转换流相当于中间商,使用时将 字节流/节点流 传给 转换流 ,再将 转换流 传给 处理流 进行最终处理(也可以不用处理流,看需求),如:BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath),"gbk")))

常用方法

  • InputStreamReader(InputStream, Charset)
  • OutputStreamWriter(OutputStream, Charset)
  • 转换流使用的 read、write的方法,实际上还是使用的节点流的 read、write 方法

打印流:PrintStream & PrintWriter

  • 只有输出流,没有输入流

  • 可以打印到屏幕上(默认),也可以打印到文件里

  • PrintStream 是 OutputStream 的子类,是字节流

  • PrintWriter 是 Writer 的子类,是字符流

  • 注意没有 close 流,仍然不会打印到文件

  • 标准输出流 System.outPrintStream 的一个实例化对象,可以使用的方法没有区别。只是标准输出流默认(且一般)将结果打印到屏幕,PrintStream 可以选择打印到文件还是打印到屏幕。如果需要改变标准输出流输出位置,用setOut

常用方法(PrintStream 和 PrintWriter通用 )

  • 打印到某个文件时,创建对象:PrintStream out = new PrintStream("D:\\test.txt");

    若打印到屏幕则将地址换成System.out

  • print:底层用的就是 write,代码:public void print(String s) { write(String.valueOf(s));},将要print的内容转化为字符串的形式,再write出来

  • 只不过多了个 null 判断,如果为空,打印 null

  • print方法相比write方法更侧重格式化输出,不需要关心数据的类型,会自动进行类型转换

与直接使用 write 方法的区别

  • 打印流是格式化输出,可以直接打印各种类型的数据,不需要手动转换位字符串,println还会手动添加换行符,而write相比是一个更底层的方法,需要手动将数据转换为字节或字节数组
  • 打印流本身自带了缓冲输入,而write还需要配合bufferedwriter等使用才有缓冲
  • 打印流更适合文本文件写入,write更适合处理非文本数据(如二进制数据)

Properties类

  • 需求:配置文件
  • 传统方法的代码比较麻烦
  • 配置文件的格式:键=值
  • 父类是 HashTable

常用方法

  • load(Reader) 加载指定配置文件

  • list 显示k-v

  • getProperty(key) 返回的是字符串

  • setProperty(key, value) 如果该文件没有这个key,则是创建。否则是修改

  • store(Writer/OutputStream, comment)

    保存的如果是中文,则会转换成unicode码

    comment 是注释,如果为 null,则没有注释,如果写了,会在配置文件最上方写明

标签:文件,Java,字节,19,write,new,序列化,节点,顺平
From: https://blog.csdn.net/YA____/article/details/140782257

相关文章

  • html中javascript点击事件后显示或隐藏某些元素时需要点击两次才生效的原因分析和优化
    html中javascript点击事件后显示或隐藏某些元素时需要点击两次才生效的原因分析和优化。原来的代码如下:<divclass="cardcardcol-sm-6col-md-4col-xl-2col-lg-2justify-content-centerbg-secondary-subtle"id="tools-trigger"><ahref="javascript:vo......
  • java基础知识汇总(一)
    PART1:Java基础知识概述与Java的下载安装1)Java语言概述:①Java的发展史:詹姆斯·高斯林(JamesGosling)1977年获得了加拿大卡尔加里大学计算机科学学士学位,1983年获得了美国卡内基梅隆大学计算机科学博士学位,毕业后到IBM工作,设计IBM第一代工作站NeWS系统,但不受重视。后来转至S......
  • Solution - Atcoder YPC2019E Odd Subrectangles
    首先对于\(0/1\)和为奇数,转化为异或为\(1\)来考虑。考虑如果已经确定了行的选取,又该如何计数。考虑对于每一列,都处理好在对应行的位置的异或值。然后记\(\operatorname{c}_0,\operatorname{c}_1\)表示列异或值为\(0/1\)的数量。知道了\(\operatorname{c}_0,\op......
  • 每日一题- CF1991G
    考场真是困傻了,这都不会横的放左边k列,竖的放上边k行,优先放能消的位置#include<bits/stdc++.h>usingnamespacestd;intt,n,m,k,q,a[105][105];chars[1005];intx[105],y[105];intmain(){ scanf("%d",&t); while(t--){ scanf("%d%d%d%d",&n,&m,&k......
  • Java 关键字、标识符、注释、常量
    关键字:被Java语言赋予特殊含义的单词,一般是使用小写字母构成。如何区分关键字?idea对关键字具有高亮的效果。但goto和const作为保留字存在。标识符:给类、接口、方法、变量等起名字时使用的字符序列起名字时的规则:1、英文大小写字母2、数字字符3、$和_起名字时的规范:1......
  • JAVA毕业设计|springboot房屋租赁系统包含文档代码讲解
     收藏点赞不迷路 关注作者有好处文末获取源码一、系统展示二、万字文档展示开发语言:Java数据库:MySQL技术:Spring+SpringMVC+MyBatis+Vue工具:IDEA/Ecilpse、Navicat、Maven 编号:springboot008一、系统展示二、万字文档展示第5章系统详细设计5.1管理员功能模......
  • JAVA毕业设计|springboot在线宠物用品交易网站的设计与实现包含文档代码讲解
    收藏点赞不迷路 关注作者有好处文末获取源码一、系统展示二、万字文档展示开发语言:Java数据库:MySQL技术:Spring+SpringMVC+MyBatis+Vue工具:IDEA/Ecilpse、Navicat、Maven 编号:springboot082一、系统展示二、万字文档展示第5章系统详细设计5.1管理员模块的......
  • Javaweb项目|停车场微信小程序的设计与实现+ssm【源码+论文+PPT+部署视频】
    我们提供多元化的技术项目服务,涵盖Java、PHP、Python等编程语言,以及前端开发、人工智能、大数据、单片机开发、ASP.NET、物联网等领域。我们还提供简历模板、面试题库和学习资料,帮助用户提升技术能力和就业竞争力。我们的服务内容包括:免费功能设计、任务书和开题报告撰写、......
  • Javaweb项目|springboot大学生就业招聘系统的设计与实现
    收藏点赞不迷路 关注作者有好处文末获取源码一、系统展示二、万字文档展示 基于springboot大学生就业招聘系统的设计与实现开发语言:Java数据库:MySQL技术:Spring+SpringMVC+MyBatis+Vue工具:IDEA/Ecilpse、Navicat、Maven 编号:springboot047一、系统展示二、万......
  • 小白快速了解的Java知识!
    Java初学习1.Java的诞生与崛起1972年,c语言诞生,其高效率,运行速度快让大批程序员为之倾倒,但是c语言的指针及其内存管理需要程序员自行操作,浪费了大量的时间以及精力,再加上c语言需要尽可能的使用c函数库,并没有像宣传的那样可以轻松的跨平台,导致部分程序员对于其暴政感到不满。1982......