22、一旦获得了一个 Charset,就可以在 Java 的 Unicode 和指定的编码格式之间进行转化,下面以 GBK 和 Unicode 之间做为例子。

从 Unicode 到 GBK:

import java.nio.charset.Charset;
import java.nio.ByteBuffer;
import java.util.Map;public class ConvCharset {public static void main(String [] args)throws Exception {Charset gbk_cset = Charset.forName("gbk");String utf_str = new String("计算所"); // utf-8 stringString gbk_str = new String(utf_str.getBytes(), gbk_cset); // gbk stringSystem.out.println(utf_str.length());System.out.println(gbk_str.length());}
}

从 GBK 到 unicode:

暂时没有成功…… 诡异。。

23、DataOutput 接口定义了以二进制格式输出,写各种类型数据的方法:

writeInt
writeByte
writeDouble
….
writeUTF

它们的写都是固定的,如 int 固定 4 字节,double 是 8。

总之是从 Java 内部类型转换到二进制表示,使用的都是大端。

对于 UTF,使用的是一个 UTF-8 的修改版本,只有 Java 虚拟机是这么用的,因此跨语言时不要使用。

DataOutputStream 实现了 DataOutput 接口,当然要用需要包装一层 FileOutputStream,甚至 Buffered 神马的,比如:

DataOutputStream out  = new DataOutputStream(new FileOutputStream("file.dat"));

24、类似的 DataInput 定义了和上面对应的读取方法。一般来说 writeInt 之后(输出成了二进制),是必须要能够从 readInt 反解析回来的。

25、RandomAccessFile 同时实现了 DataInput 和 DataOutput,主要是用于磁盘上的文件:

RandomAccessFile in = new RandomAccessFile("file.dat", "r");
RandomAccessFile inOut = new RandomAccessFile("file.dat", "r");

这个模式还可以选 rws 和 rwd,rws 要求每个 I/O 操作都要同步,rwd 可以将多次 I/O 合并成一次。

seek() 用于将文件指针放到文件内部任何位置。

getFilePointer() 返回当前文件指针的位置。

length() 返回文件总字节数。

关注公众号:「Java知己」,发送「1024」,免费领取 30 本经典编程书籍。​与 10 万程序员一起进步。每天更新Java知识哦,期待你的到来!

26、下面的例子使用 **DataOutputStream、RandomAccessFile **等来实现固定字节 Record 的读取和随机访问。

切记:String 的一个 char 占用两个字节!!

import java.io.*;public class RAFTest {public static void main(String [] args) {Person [] ps = new Person[3];ps[0] = new Person("lxr", 1);ps[1] = new Person("lhy", 2);ps[2] = new Person("coder3", 3);int max_str = 80;int REC_LEN = max_str*2+4;try {//WriteDataOutputStream out = new DataOutputStream(new FileOutputStream("person.dat"));for(int i=0; i<ps.length; i++) {ps[i].Write(max_str, out);}out.close();//Read one by one and outputRandomAccessFile raf = new RandomAccessFile("person.dat", "r");int nps = (int)raf.length()/REC_LEN;Person [] ps2 = new Person[nps];for(int i=0; i< nps; i++) {raf.seek(i*REC_LEN);ps2[i] = new Person();ps2[i].Read(max_str, raf);System.out.println(ps2[i]);}raf.close();} catch(Exception e) {e.printStackTrace();}}
}class Person {public Person(String name, int id) {this.name = name;this.id = id;}public Person() {}public String getName() {return name;}public int getId() {return id;}public void setName(String name) {this.name = name;}public void setId(int id) {this.id = id;}public void Write(int str_len, DataOutput out) throws IOException {//Write name, at most str_len *2 bytesfor(int i=0; i < str_len; i++) {char c = 0;if(i<name.length()) {c = name.charAt(i);}out.writeChar(c);}//Output idout.writeInt(id);}public void Read(int str_len, DataInput in) throws IOException {//Read name, skip if len < str_lenStringBuilder sb = new StringBuilder();for(int i=0; i < str_len; i++) {char c = in.readChar();if(c!=0) {sb.append(c);}}this.name = sb.toString();//Read idthis.id = in.readInt();}public String toString() {return this.name + " " + this.id;}private String name;private int id;
}

27、ZipInputStream 和 ZipOutputStream 是用于操作 zip 文件的。

它们都是嵌套结构,一个 Stream 内含若干个 ZipEntry(就是 Zip 内置的文件)

对于 ZipInputStream,需要首先调用 getNextEntry(),之后再调用 read(),当然也可以用其他 DataInput 等包装读取。当 - 1 时,表示当前 entry 完毕,需要先调用 CloseEntry(),然后再读取 getNextEntry(),直到返回 null,表示全部都读取完毕。

对于 ZipOutputStream,新建一个文件时,需要 putNextEntry(),写入完毕后,调用 closeEntry()。

一个读写 zip 文件的例子如下:

import java.io.*;
import java.util.*;
import java.util.zip.*;public class ZipTest {public static void main(String [] args) throws Exception {//Write an zip fileZipOutputStream zout = new ZipOutputStream(new FileOutputStream("test.zip"));DataOutputStream dout = new DataOutputStream(zout);zout.putNextEntry(new ZipEntry("file1.txt"));dout.writeUTF(new String("I'm file1.txt"));zout.closeEntry();zout.putNextEntry(new ZipEntry("file2.txt"));dout.writeUTF(new String("I'm file2.txt"));zout.closeEntry();dout.close();zout.close();//Read zip fileZipInputStream zin = new ZipInputStream(new FileInputStream("test.zip"));ZipEntry entry = null;while( (entry = zin.getNextEntry() )!=null) {Scanner scan = new Scanner(zin); //一定要新建Scanner!!String str = "";while(scan.hasNextLine()){str+=scan.nextLine();str+="\n";}System.out.println(entry.getName());System.out.println(str);System.out.println();zin.closeEntry();}zin.close();}
}

需要注意的是,读取时,每切换一个 Entry,要新建一个 Scanner!!!

28、Java 提供了 “对象序列化” 机制,可以将任何对象写入到流中,并在将来取回。

29、ObjectOutputStream 用于输出对象,ObjectInputStream 用于读取。对象必须实现了 Serialize 接口。但这个接口不含任何方法。所以序列化理论上不需要做其他事情,Stream 会自动扫描所有域,并逐一序列化 / 反序列化。

30、为了保证对象的一致性(一个对象可能被多个其他对象引用)。每个对象内部有唯一的 ID。

31、相同序号重复出现将被替换为只存储对象序号的引用。

32、如果不想让某个域被序列化,将其表为** transient**(瞬时的)即可,如:

public class LabelPoint implements Serializable {private String label;private transient int tmp_id;
}

33、如果想大规模重写序列化、反序列化,可以自己写 readObject 和 writeObject:

private void writeObject(ObjectOutputStream out);
private void readObject(ObjectInputStream out);

34、如果想同时重写超类中的数据域,则要使用 **Externalizable **接口。如果你对继承结构复杂的类序列化,并且想要更快的性能,应该使用 Externalizable,它会更快。

35、对于 Enum 的枚举,序列化可以正常工作。对于 public static final xxx 这种定义的常量,一般不会正常工作,此时慎重使用对象序列化。

36、因为序列化会存储类结构的指纹,因此如果类结构变化了,想搞一个版本号怎么办?简单,加上:

public static final long serialVersionUID = 42L;

37、其实也可以用序列化做** clone**:先 Output 再 Input。当然这比 clone 慢很多。

38、前面的各种 Stream 关注的是文件内容。而文件的管理,与文件系统,则由 File 类完成。

File f = new File("file.dat");
System.out.println(f.getAbsolutePath());
System.out.println(f.exists());

39、File 还可以有 dir 和 name 的构造:

File(File dir, String name);

File 既表示文件也可以是目录,用 isFile() 和 isDirectory() 区分。

File 中的 separator 是路径分隔符,windows 为 \,Linux 为 /

File 还有很多功能,如创建临时文件,遍历目录等等。。

40、JDK 1.4 后引入了** New I/O(java.nio)**,包含了下述操作系统的新特性:

  • 字符编码
  • 非阻塞 I/O
  • 内存映射文件
  • 文件加锁

41、操作系统支持将文件映射到内存的一块中进行操作,以减少不断 I/O 的时间浪费。

用 nio 进行文件映射很简单:

(1) 和往常一样打开 FileInputStream
(2)FileChannel channel = stream.getChannel() 获得这个通道。
(3)FileChannel 的 map 方法获得映射:

public abstract MappedByteBuffer map(FileChannel.MapMode mode,long position,long size);

有三种默认:只读、可写、私人(可以更改,但不会更新到文件)。

之后就可以用 ByteBuffer 进行操作了。

可以一次 get() 出一个 byte,也可以用 getInt(),getDouble() 等以二进制的方式读取基本类型。可以用 order() 设置大、小端。

42、Buffer 这个超类和其子类 IntBuffer、ByteBuffer、DoubleBuffer 等,也是 nio 新引进的。

43、缓冲区是相同类型的信息块,每个缓冲区都有:固定的容量(设置的)、读写位置、界限(超出后无意义)、标记(用于重复读等)。

44、缓冲区主要是用来循环执行 “写、读” 等操作。
(1) 初始:位置为 0,界限等于容量,不断用 put 写入到缓冲区。
(2) 当数据全写完或者到达容量限制时,需要切换到读操作。
(3) 调用 flip,将位置复位到 0。
(4) 此时不断 get,当 remainning() 返回正是,表示还有未读取完的。最后调用 clear() 重回写状态
如果要重新读入,可以用 rewind 或者 mark/reset。

关于 Buffer 和 Channel 可以围观一下这篇神文,解释的很好:

http://www.cnblogs.com/focusj/archive/2011/11/03/2231583.html

45、有时候我们想对文件加锁,还是用 FileChannel,它有 lock() 方法:

public final FileLock lock()

它会阻塞,直到获得一个锁,也可以用 trylock,不阻塞。

lock 也有设置独占、共享的版本:

public abstract FileLock lock(long position,long size,boolean shared)

如果 shared=true,则共享,但放置别人独占。false 则独占,排斥其他全部。

46、锁为 JVM 不可重入(同一个 JVM 启动的类不能全占有),实际是进程不可重入。

47、正则表达式,模式化的字符串:

[Jj]ava.+

匹配 Java、java,java/Java**

正则表达式的规则不再多说了,用的太多了。

Java 与正则相关的 API 主要是 Pattern 和 Matcher 类。

Pattern pattern = Pattern.compile("patternString");
Matcher matcher = pattern.matcher("string to be matched");
//模式1:匹配全串
if (matcher.matches()) {
...
}
//模式2:匹配子串
while(matcher.find()) {
......
}

compile 时可以加选项:

CASE_INSENSITIVE:大小写不敏感
MULTILINE:可以跨行
DOTALL:匹配所有终止。

Java 的正则也支持组群。

group(int gourpNum)

0 是全串,从 1 开始,按照在 pattern 中按照括号的逐一递增排序。

Matcher 的 replaceAll 替换所有,之中可以用 $n 表示引用组群。

Pattern 的 split 可以用正则分割字符串。

一个提取网页中所有 ,并把所有 url 替换为 #的例子:

import java.io.*;
import java.util.regex.*;public class RETest {public static void main(String [] args) throws IOException {//Read htmlBufferedReader reader = new BufferedReader(new FileReader("test.html"));char buf [] = new char[1024];int len;StringBuilder sb = new StringBuilder();while((len = reader.read(buf, 0, 1024))!=-1) {sb.append(buf, 0, len);}String html = sb.toString();//System.out.println(html);reader.close();//Regular ExpPattern pt = Pattern.compile("<a\\s.*?href=\"([^\"]+)\"[^>]*>(.*?)</a>", Pattern.MULTILINE|Pattern.DOTALL);Matcher ma = pt.matcher(html);while(ma.find()) {int ng = ma.groupCount();if(ng>0){System.out.println(ma.group(1));}}}
}

本章完毕。

关注公众号:「Java知己」,发送「1024」,免费领取 30 本经典编程书籍。​与 10 万程序员一起进步。每天更新Java知识哦,期待你的到来!

相关文章:

Java 核心技术卷 II(第 8 版) – 读书笔记 – 第 1 章(上)

推荐文章:

反射是框架设计的灵魂

腾讯工作近十年大佬:不是我打击你!你可能真的不会写Java

Java 核心技术卷 II(第 8 版) – 读书笔记 – 第 1 章(下)相关推荐

  1. 《Java编程思想》第四版读书笔记 第四章

    2019独角兽企业重金招聘Python工程师标准>>> 4.3 逗号操作费仅用于for循环控制表达式的初始化部分和步进控制部分.初始化部分用于定义任意多个具有相同类型的变量: for ...

  2. 新书推荐 | Java核心技术 卷II 高级特性(原书第11版)

    新书推荐 <Java核心技术 卷II 高级特性(原书第11版)> 长按二维码 了解及购买 全新第11版!针对Java SE9.10.11全面更新!Java领域极具影响力和价值的著作之一,与 ...

  3. Java编程思想+Effective Java+Java核心技术+Java核心技术 卷II+Java语言程序设计(中文+英文+源码)

    Java四大名著(中文+英文+源码 ) 传说中的java四大名著,分享出来方便大家学习! 书名如下: Java编程思想 Effective Java(第2版) Java核心技术 卷I(第8版) Jav ...

  4. 《Java 核心技术卷1 第10版》学习笔记------异常

    异常处理的任务就是将控制权从错误产生的地方转移给能够处理这种情况的错误处理器 . 7.1.1 异常分类 在 Java 程序设计语言中, 异常对象都是派生于 Throwable 类的一个实例 . 稍后还 ...

  5. Java核心技术 卷II 高级特性 原书第9版pdf

    下载地址:网盘下载 内容简介  · · · · · · Java领域最有影响力和价值的著作之一,由拥有20多年教学与研究经验的资深Java技术专家撰写(获Jolt大奖),与<Java编程思想&g ...

  6. 《Java 核心技术卷1 第10版》学习笔记 ------ 泛型【进阶】

    这部分主要是结合 Java 虚拟机实现泛型的原理进一步研究如何更好的使用泛型. 8.5 泛型代码和虚拟机 虚拟机没有泛型类型对象---所有对象都属于普通类.所以编译器在编译的时候会进行类型擦除操作. ...

  7. 《Java 核心技术卷1 第10版》学习笔记 ------ 泛型【基础】

    泛型从Java SE 5.0 中开始出现,是 Java 程序设计语言从 1.0 版本发布以来,变化最大的部分. 使用泛型机制编写的程序代码要比那些杂乱地使用 Object 变量,然后再进行强制类型转换 ...

  8. 《Java 核心技术卷1 第10版》学习笔记------对象克隆【对象拷贝】

    由于克隆并不太常见,而且有关的细节技术性很强,你可能只是想稍做了解,等真正需要时再深人学习. 先来回忆为一个包含对象引用的变量建立副本时会发生什么 .原变量和副本都是同一个对象的引用: Employe ...

  9. 《Java 核心技术卷1 第10版》学习笔记------调试技巧

    调试器是 Eclipse . NetBeans 这类专业集成开发环境的一部分 . 在启动调试器之前, 本节先给出一些有价值的建议 . 1 ) 可以用下面的方法打印或记录任意变量的值 : System. ...

最新文章

  1. 腾讯某员工哀叹:门口卖早点的送孩子去私立了,一年学费顶我一年工资!
  2. 福特数据总监:汽车业的大数据框架如何构建?
  3. HSmartWindowControl 之 摄像头实时显示( 使用 WPF )
  4. 13. Leetcode 349. 两个数组的交集 (数组-分离双指针)
  5. java有参数 无参数方法
  6. 前端开发者必备的代码开源平台,记得收藏转发!
  7. go编译so win10_windows搭建Go语言交叉编译环境
  8. 用python程序编写二元多项式_Python多项式回归的实现方法
  9. 什么?你还不知道IDEA Debug界面的按钮都是干啥用的?快进来补补课~
  10. pycharm编程工具自带python环境吗_pycharm+PyQt5+python最新开发环境配置(踩坑)
  11. Python 语言 Hello world
  12. 智能美观网速快 有这样的无线路由吗?
  13. 1. MFC编程——变量命名规则
  14. Atitit nlp用到的技术与常见类库 目录 1. 常用的技术 1 1.1. 语言处理基础技术 分词 相似度等 1 1.2. 新闻摘要 2 1.3. 情感倾向分析 2 1.4. 文章标签 2 1.
  15. MongoDB介绍与部署使用
  16. c语言代码量统计工具
  17. 励志:滴滴打车App初期是怎么推广的?
  18. Redis集群--Cluster--节点通信的过程(原理)
  19. 知云文献翻译打不开_科研福音,论文翻译神器系列!
  20. C# WinForm菜单和工具栏控件

热门文章

  1. 爱快可迅速普及家庭专线?
  2. excel锁定单元格不能修改_【软件应用】工程中经常运用的Excel技巧(附教程下载)...
  3. 2020南京航空航天大学计算机科学与技术学院软件工程复试/面试经验分享
  4. Unity使用反射探头实现地面的镜面反射
  5. Android获取系统邮件账号
  6. 小学计算机管理员总结,计算机管理教学个人总结范文
  7. 在职研究生读计算机专业,读计算机专业在职研究生让我择业自如高升有望
  8. 教育行业下半场强势到来!专访FCG教育链Edward Cai:从互联网教学到“链教学”,让天下没有不公平的教育...
  9. stm32f407zgt6与stm32f407vet6的通用io口差别
  10. 5个方法将不带www的根域名301重定向到www主域名