IO.2(须知少时凌云志,曾许人间第一流)
字符流
既然字节流可以操作所有的文件,为什么还有字符流呢
如果利用字节流,把文本中的中文,读取到内存中,有可能出现乱码
如果利用字节流,把中文写到文本文件中,也有可能出现乱码
如果是英文 可以打印出来,中文就会出现乱码
如果字节流写入到文本中也会出现乱码
基础知识:
计算机存储方式的信息是用二进制数表示的
按照某种规则,将字符变成二进制,再存储到计算机中,称为编码
按照同样的规则,将存储在计算机中的二进制数解析显示出来,称为解码
编码和节码的方式必须一致,否之会导致乱码
简单理解:
存储一个字符a,首先再码表中查到对应的数字是97,然后转成二进制进行存储
读取的时候,先把二进制解析出来,再转成97,通过97查找到对应的字符应该是a
编码表简单理解:
ASCII字符集:
ASCII(American Standard Code for Information Interchanae,美国信息交换标准代码):包括了数字,大小写字符和一些常见的标点符号
注意:ASCII码表是没有中文的
GBK:
window系统默认的码表。兼容了ASCII码表,也包含了21003个汉字,并支持繁体汉字以及部分日韩文字
注意:GBK是中国的码表,一个中文以两个字节的形式存储,但不包含世界上所有国家的文字
Unicode码表:
由国际组织ISO定制,是统一的万国码,计算机科学领域里的一项业界标准,容纳世界上大多数国家所有常见的文字和符号
但是因为表示的字符太多,所以Unicode码表中的数字不是直接以二进制的形式存储到计算机的
会先通过UTF-7,UTF-7.5,UTF-8,UTF-16,以及UTF-32进行编码,再存储到计算机,其中最为常见的UTF-8
注意:Unicode是万国码,以UTF-8编码后一个中文以三个字节的形式存储
重点:windows默认使用的码表为:GBK,一个字符两个字节
idea和其他工具默认使用Unicode的UTF-8的编码格式,一个中文三个字节
字节串中的编码节码问题
编码:
byte[] getBytes():使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中
byte[] getBytes(String charsetName):使用用户指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中
解码:
String(byte[] bytes):通过使用平台默认的字符集解码指定的字节数组来构造新的String
String(byte[] bytes,String charseName):通过指定的字符集节码指定的字节数组来构造新的String
代码:
public class test15 {public static void main(String[] args) throws UnsupportedEncodingException {// 编码:// byte[] getBytes():使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中// byte[] getBytes(String charsetName):使用用户指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中//String s="我以后一定会称为高级开发";//利用idea默认的UTF-8将中文编码为一系列的字节byte[] bytes=s.getBytes();System.out.println(Arrays.toString(bytes));//[-26, -120, -111, -28, -69, -91, -27, -112, -114, -28, -72, -128, -27, -82, -102, -28, -68, -102, -25, -89, -80, -28, -72,// -70, -23, -85, -104, -25, -70, -89, -27, -68, -128, -27, -113, -111]byte[] bytes1 = s.getBytes("GBK");System.out.println(Arrays.toString(bytes1));//[-50, -46, -46, -44, -70, -13, -46, -69, -74, -88, -69, -31, -77, -58, -50, -86, -72, -33, -68, -74, -65, -86, -73, -94]// 解码:String(byte[] bytes):通过使用平台默认的字符集解码指定的字节数组来构造新的StringString(byte[] bytes,String charseName):通过指定的字符集节码指定的字节数组来构造新的Stringbyte[] bytes2={-26, -120, -111, -28, -69, -91, -27, -112, -114, -28, -72, -128, -27, -82, -102, -28, -68, -102, -25, -89, -80, -28, -72, -70, -23, -85, -104, -25, -70, -89, -27, -68, -128, -27, -113, -111};byte[] bytes3={-50, -46, -46, -44, -70, -13, -46, -69, -74, -88, -69, -31, -77, -58, -50, -86, -72, -33, -68, -74, -65, -86, -73, -94};//默认使用UTF-8进行解析String s1=new String(bytes2);System.out.println(s1);//我以后一定会称为高级开发//利用只当GBK进行解码String s2=new String(bytes3,"GBK");System.out.println(s2);//我以后一定会称为高级开发}}
字节流读取文本文件出现乱码的原因
因为字节流一次读一个字节,而不管是GBK还是UTF-8一个中文都是多个字符的,而字节流每次只能读取其中一部分,所以就会出现乱码问题
字符流读取中文的过程
字符流=字节流+编码表
基础知识:
不管再那张码表中,中文的第一个字节一定是负数
小结:
1.想要进行拷贝,一律使用字节流或者字节缓冲流
2.想要把文本文件中的数据读取到内存中,请使用字符输入流
想要把内存中的数据写道文本文件中,请使用字符输出流
3.GBK码表一个中文两个字节,UTF-8编码格式一个中文三个字节
字符流写数据:
步骤:1.创建字符输出流对象
2.写数据
3.释放资源
字符流写数据的5中方式
void write(int c) 写一个字符
void write(char[] cbuf) 写一个字符数组
void write(char[] cbuf,int off,int len) 写出字符数组的一部分
void write(String str) 写一个字符串
void write(String str,int off,int len) 写一个字符串的一部分
代码:
public class test16 {public static void main(String[] args) throws IOException {// 步骤:1.创建字符输出流对象// 2.写数据// 3.释放资源// 字符流写数据的5中方式// void write(int c) 写一个字符//字符流的底层就是字节流//下边两种创建方式都可以//FileWriter fw = new FileWriter(new File("fileIo\\a.txt"));FileWriter fw= new FileWriter("fileIo\\a.txt");//写出数据fw.write(98);fw.write(97);fw.write(99);//释放资源fw.close();// void write(char[] cbuf) 写一个字符数组char[] chars={97,98,99};fw.write(chars);// void write(char[] cbuf,int off,int len) 写出字符数组的一部分char[] chars1={97,98,99,100};fw.write(chars1,0,2);//从0所以开始写入三个// void write(String str) 写一个字符串String s="我很厉害No1";fw.write(s);// void write(String str,int off,int len) 写一个字符串的一部分fw.write(s,0,2);//每次运行完 切记要关掉流 不然你内存多少G都不够 这坑踩过}}
字符流写数据 注意事项
1.创建字符输出流对象
如果文件不存在,就创建,但是要保证父级路径存在
如果文件存在就清空
2.写数据
写出int类型的整数,实际写出的是整数再码表上对应的字母
写出字符串数据,是把字符串本身原样写出
3.释放资源
每次释放必须关闭,不然电脑内存会直接溢出,直至没有空间继续写
flush和close方法
flush() 刷新流,还可以继续写数据
close() 关闭流,释放资源,但是在关闭之前会先刷新流,一旦关闭,就不能再写数据
代码:
public class test17 {public static void main(String[] args) throws IOException {// flush() 刷新流,还可以继续写数据// close() 关闭流,释放资源,但是在关闭之前会先刷新流,一旦关闭,就不能再写数据FileWriter fw = new FileWriter("test//a.txt");fw.write("阿星在努力");//这个时候运行并不会打印数据// fw.flush(); //fw.write("666");//fw.flush();fw.close();fw.write("aaa");//Stream close}}
字符流读的两种方式
单个字符读取:
public class test18 {public static void main(String[] args) throws IOException {//创建字符输入流的对象//底层是字节流+编码表// FileReader fr = new FileReader(new File("test\\a.txt"));FileReader fr = new FileReader("fileIo\\a.txt");//读取数据 一次读取一个字符int ch;while ((ch=fr.read())!=-1){System.out.println((char) ch);}//释放资源fr.close();}}
多个字符读取:
public class test19 {public static void main(String[] args) throws IOException {//一次读取多个字符//创建对象FileReader fr = new FileReader("fileIo\\a.txt");//创建一个数组char[] chars = new char[1024];int len;//read 读取 一次读取多个字符//他把读到的字符都存入到了chars数组//返回值:表示本次读到了多少个字符while ((len=fr.read())!=-1){System.out.println(new String(chars,0,len));}fr.close();}}
写一个练习
需求:用户输入的用户名和密码保存到本地实现永久化存储 用户名占一行,密码占一行
步骤:1.写一个键盘录入用户名和密码
2.将用户名和密码写到本地文件中
代码:
public class test20 {public static void main(String[] args) throws Exception {//1.键盘录入用户名和密码Scanner sc=new Scanner(System.in);System.out.println("请录入用户名");String username = sc.next();System.out.println("请录入密码");String password = sc.next();//2.分别把用户名和密码写到本地文件FileWriter fw = new FileWriter("filelo\\a.txt");//将用户名和密码写到文件中fw.write(username);//写出一个回车换行符fw.write("\r\n");fw.write(password);//刷新流fw.flush();//释放资源fw.close();}}
字符缓冲流
BufferedWriter:可以将数据高效的写出
BufferedReader:可以将数据高效的读取到内存
代码实例:
public class test21 {public static void main(String[] args) throws IOException {//字符缓冲输入流BufferedReader br=new BufferedReader(new FileReader("filelo\\a.txt"));//读取数据char[] chars=new char[1024];int len;while ((len=br.read())!=-1){System.out.println(new String(chars,0,len));}br.close();}}
字符缓冲输出流
BufferedWrited:可以将数据高效的写出
BufferedReader:可以将数据高效的读取到内存
构造方法:
BufferedWrited(Writer out);
BufferedReader(Reader in);
代码:
public class test22 {public static void main(String[] args) throws Exception {//字符缓冲输出流BufferedWriter bw=new BufferedWriter(new FileWriter("filelo\\a.txt"));//写出数据bw.write(98);char[] chars=new char[1024];bw.write(chars);bw.write(chars,0,3);bw.write("有梦终会达");String s="adsafsa";bw.write(s,0,3);bw.flush();bw.close();}}
字符缓冲流特有功能
BufferedWrited:
void newLine(): 写一行行分隔符,行分隔符字符串由系统属性定义
BufferedReader:
public StringReadLine():读一行文字,结果包含行的内容的字符串,不包括任何行终止字符,如果流的结尾以及到达,则为null
代码实例:
public class test23 {public static void main(String[] args) throws Exception {//创建对象BufferedWriter bw = new BufferedWriter(new FileWriter("filelo\\a.txt"));//写出数据bw.write("在黑夜里发光");//跨平台的回车换行bw.newLine();bw.write("asdasd");bw.newLine();bw.write("153123");//刷新流 释放资源bw.flush();bw.close();}}
代码实例:
public class test24 {
public static void main(String[] args) throws Exception {
//创建对象
BufferedReader br=new BufferedReader(new FileReader("filelo\\a.txt"));
//读取数据
//在之前,读不到数据返回就是-1,显示现在readLine方法读不到数据就返回null
String line = br.readLine();
String line1 = br.readLine();
String line2 = br.readLine();
System.out.println(line);
System.out.println(line1);
System.out.println(line2);//如果这一行没有数据 就在控制台输出null
//释放资源
br.close();
}
}
用循环做一个改进
public class test25 {public static void main(String[] args)throws Exception {//创建对象BufferedReader br=new BufferedReader(new FileReader("filelo\\a.txt"));//读取数据//在之前,读不到数据返回就是-1,显示现在readLine方法读不到数据就返回nullString line;//可以读取一整行数据,一直都,读到回车换行为止//但是他不会读取回车换行符while ((line=br.readLine())!=null){System.out.println(line);}//释放资源br.close();}}
案例:读取文件中的数据排序后再次写到本地 文件中的数据 9 8 2 4 3 1 5 3
1.读取数据
2.排序
3.写到本地
代码:
public class test26 {public static void main(String[] args) throws Exception {// 1.读取数据BufferedReader br=new BufferedReader(new FileReader("filelo\\a.txt"));这个不能提前创建 如果a.txt 有东西 会直接清空 不能写道BufferedReader定义的下一行//BufferedWriter bw=new BufferedWriter(new FileWriter("filelo\\a.txt"));String line=br.readLine();System.out.println("读取到的数据为"+line);br.close();// 2.排序//按照空格进行切割String[] s = line.split(" ");//把字符串类型的数组变成int类型int[] arr=new int[s.length];//遍历s数组,可以进行类型转换for (int i = 0; i < s.length; i++) {String smallStr= s[i];int number = Integer.parseInt(smallStr);//把转换后的结果存到arr中arr[i] =number;}Arrays.sort(arr);System.out.println(Arrays.toString(arr));// 3.写到本地BufferedWriter bw=new BufferedWriter(new FileWriter("filelo\\a.txt"));for (int i = 0; i < arr.length; i++) {bw.write(arr[i]+" ");bw.flush();}bw.close();}}
I
转换流:
转换输入流:InputStreamReader
转换输出流:OutputStreamWriter
转换流的使用场景
JDK11之前,指定编码读写
之前的方法会产生乱码
public class test27 {public static void main(String[] args) throws IOException {//这个方法直接读取会产生乱码//因为文件时GBK码表//而IDEA 默认时UTF-8 所以两者不一致 就会出现乱码FileReader fr = new FileReader("D:\\a.txt");int ch;while ((ch=fr.read())!=-1){System.out.println((char) ch);}fr.close();}
}
转换流的实例:
public class test27 {public static void main(String[] args) throws IOException {//第二个参数 大小写都可以 指定编码读InputStreamReader isr = new InputStreamReader(new FileInputStream("D\\a.txt"), "GBK");int ch;while ((ch=isr.read())!=-1){System.out.println((char) ch);}isr.close();OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("D\\a.txt"),"GBK");osw.write("我爱学习");osw.close();//JDK11之后,字符流新推出了一个构造,也可以指定编码表FileReader fr = new FileReader("D\\a.txt", Charset.forName("gbk"));int ch1;while ((ch1=isr.read())!=-1){System.out.println((char) ch1);}}
}
对象操作流
特点:可以把对象以字节的形式写道本地文件,直接打开文件,是读不懂的,需要再次用对象操作流读到内存中
对象操作流分为两类:对象操作输入流和对象操作输出流
对象操作输出流(对象序列化流):就是将对象写到本地文件中,或者网络中传输对象
对象操作输入流(对象反序列化流):把写到本地文件中的对象读取到内存中,或者接收网络中传输的对象
序列化代码
User类: public class User implements Serializable {
//如果这个类的对象能被序列化,那么这个类必须要实现一个Serializable接口
//Serializable 称之为一个标记性接口,里面没有任何抽象方法 只要一个类实现了这个接口,那么就表示这个类的对象可以被序列化
private String username;private String password;public User() {}public User(String username, String password) {this.username = username;this.password = password;}@Overridepublic String toString() {return "User{" +"username='" + username + '\'' +", password='" + password + '\'' +'}';}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}
测试类代码:
public class test28 {public static void main(String[] args) throws Exception {User user=new User("zhangsan","abc");ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("a.txt"));oos.writeObject(user);oos.close();}
}
对象反序列化
public class test29 {public static void main(String[] args) throws Exception {ObjectInputStream ois=new ObjectInputStream(new FileInputStream("a.txt"));User o = (User) ois.readObject();System.out.println(o);ois.close();}
}
注意点:用对象序列化一个对象后,假如我们修改了对象所属的Javabean类,读取会出现问题
SerialVersionUID 序列化
如果我们自己没有定义,那么虚拟机会根据类中的信息自动计算出一个序列号
如果我们修改了类中的信息,虚拟机就会再次计算出一个序列号
第一步 把User对象序列化到本地 虚拟机会创建一个序列号
第二步 修改了javabean类 导致虚拟机重新创建了一个序列号,两者不一致
第三步 把文件中的对象读到内存,本地中的序列号和类中的序列号就不一致了
解决
不让虚拟机帮我们计算,我们手动给出,而且这个值不变
在User类中加入 private static final long serialVerSionUID =1L;
public class User implements Serializable {//如果这个类的对象能被序列化,那么这个类必须要实现一个Serializable接口//Serializable 称之为一个标记性接口,里面没有任何抽象方法 只要一个类实现了这个接口,那么就表示这个类的对象可以被序列化// SerialVersionUID 序列化
// 如果我们自己没有定义,那么虚拟机会根据类中的信息自动计算出一个序列号
// 如果我们修改了类中的信息,虚拟机就会再次计算出一个序列号
// 第一步 把User对象序列化到本地 虚拟机会创建一个序列号
// 第二步 修改了javabean类 导致虚拟机重新创建了一个序列号,两者不一致
// 第三步 把文件中的对象读到内存,本地中的序列号和类中的序列号就不一致了
// 解决
// 不让虚拟机帮我们计算,我们手动给出,而且这个值不变private static final long serialVerSionUID =1L;private String username;private String password;public User() {}public User(String username, String password) {this.username = username;this.password = password;}@Overridepublic String toString() {return "User{" +"username='" + username + '\'' +", password='" + password + '\'' +'}';}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}
IO.2(须知少时凌云志,曾许人间第一流)相关推荐
- 须知年少凌云志 曾许人间第一流
我的第一篇博客,新的开始,记录点滴学习历程~ 欢迎你的到来~ 我是(Who am I?) 今年19岁的我,是一名双非院校IT领域(实际的专业是最近几年特别火热的人工智能)的既平凡又普通大二在读本科生: ...
- 须知少年凌云志,曾许天下第一流
岁月如梭,韶光易逝.重回首,去时年,揽尽风雨苦亦甜.夜阑珊,读无眠,听尽春言,每天都是新的一片,不再清闲,望着洒满月光的星星一路向前. 余忆年少时,天真无邪,意气风发,或青衫白马仗剑天涯,或洋洋洒洒, ...
- 少时须有凌云志,曾许天下第一流!!!
About my first blog: a:About myself: 我是来自武工大的一名21级小萌新,对编程有着浓烈的兴趣爱好^^(简单的介绍一下 b:Goal: 目标嘛,想必大家都一样!!(进 ...
- 2019科学突破奖揭晓 庄小威陈志坚许晨阳上榜
来源:科学网 10月17日,科学突破奖(Breakthrough Prize)名单揭晓.总计2200万美元的奖金分别给了婴儿死亡主要遗传因素治疗.超分辨率成像.发现一种新型电子材料以及其他重大突破. ...
- 陈玉龙:永怀少年心 不改凌云志
点击查看活动详情:https://t.csdnimg.cn/L4B8 社区介绍: CSDN高校俱乐部是公益性技术社团,以提升高校大学生技术能力.为行业提供人才储备.为国家数字化战略贡献力量为使命,链接 ...
- 拟合算法(模型+代码)
拟合的结果是得到一个确定的曲线 最小二乘法的几何解释: argmin 存在参数k,b使括号里的值最小 第一种有绝对值,不易求导(求导在求最小值),计算较为复杂:所以我们往往使用第二种定义,也正是最小二 ...
- 轻松简单实现Android设备重启的两种方式
" 须知少时凌云志,曾许人间第一流 " 在<风犬少年的天空>中刘闻钦下线时,嘴里念叨的就是这句,我们何尝不是这样的人呢,年轻时的凌云大志,曾决心要做人间第一流的人物,干 ...
- 长大后的我们为何贪恋年少?
长大后的我们,之所以会再次贪恋年少的日子,是因为我们贪恋的其实不是时间,而是年少时纯粹的灵魂和懵懂的情愫. 最简单的情愫往往震慑心扉,回味起来,温柔又轻盈-- 而这种真切的情愫,在经历了数十年的人生之 ...
- 断章取义:时光不负有心人
知识来源:网络 星光不问赶路人, 时光不负有心人, 你只管努力, 上天自有安排 <易经>有云:"取法乎上,仅得其中:取法乎中,仅得其下:取法其下,无所得矣." 求其上者 ...
最新文章
- 教你辨别36k纯数据科学家
- PLSQL的DBMS_GETLINE
- Button的使用(六):ToggleButton
- Py之twisted:Python库之twisted简介、安装、使用方法等详细攻略
- if you canget up early
- 如何恢复ORACLE数据(冷备份)
- relative与absolute相结合
- [BAT] 执行xcopy命令后出现Invalid num of parameters错误的解决办法
- pyinstaller安装_如何打包Python Web项目,实现免安装一键启动?
- mysql工具分页原理_高效的mysql分页方法及原理
- Oracle中级篇-物化视图
- html ubb c,UBB代码和HTML代码的区别
- Ubuntu安装Yafu方法及资料
- 怪兽充电启动招股:2020年业绩下滑五成,小米、高瓴参与认购
- Zemax操作--7(坐标断点)
- 程序员和码农有什么不同?从这三个单词就看得出来
- 微信 客服消息 发送 微信会回调三次的问题
- 微信扫描PC端二维码跳转到小程序确认登录通过WebSocket来获取用户信息达到PC端登录
- 基于angularjs的单页面实例_angularjs网站开发实例
- 国产服务器上(银河麒麟)上玩转Golang