Java——再看IO
一。编码问题
- utf-8编码中,一个中文占3个字节,一个英文占1个字节;gbk编码中,一个中文占2个字节,一个英文占1个字节。
- Java是双字节编码,为utf-16be编码,是说一个字符(无论中文还是英文,都占用2个字节)。因此如果这么问:Java字符串中一个字符可以放一个中文吗?是可以的!
- 如果一直某个字节序列的编码方式,当我们想将它还原成字符串时,应明确指定其编码格式,否则会出现乱码。
- 文本文件就是字节序列,可以是任意编码的字节序列。如果在中文机器上,直接创建文本文件,该文本文件只认识ANSI编码
public static void main(String[] args) throws UnsupportedEncodingException {
// TODO Auto-generated method stub /*
* 在utf-8编码中中文占3个字节,而bgk编码中中文占2个字节
*/
String s = "慕课ABC";
byte[] byte1 = s.getBytes();
for(byte b : byte1) //byte 8bits, int 32 bits. xx vs xxxxxxxx
System.out.print(Integer.toHexString(b & 0xff) + " "); //e6 85 95 e8 af be 41 42 43 (code: utf-8)
System.out.println(); byte[] byte2 = s.getBytes("gbk");
for(byte b : byte2)
System.out.print(Integer.toHexString(b & 0xff) + " "); //c4 bd bf ce 41 42 43 /*
* java是双字节编码,utf-16be编码。意思是Java里的字符串的一个字符占用2个字节
* 面试官会问:Java一个字符中可不可以放汉字呢?如果是gbk编码,是可以的。
*/
System.out.println();
byte[] byte3 = s.getBytes("utf-16be");
for(byte b : byte3)
System.out.print(Integer.toHexString(b & 0xff) + " "); //61 55(慕) 8b fe(课) 0 41(A) 0 42(B) 0 43(C) System.out.println();
String s1 = new String(byte3);
System.out.println(s1); //乱码
String s2 = new String(byte3, "utf-16be");
System.out.println(s2); //慕课ABC }
二。File类的使用
- java.io.File类用于表示文件(目录);
- File类值用于表示文件(目录 )的信息(名称、大小等),不能用于文件内容的访问。
- 静态方法:File.seperator可以直接当成分隔符使用,无论在什么系统下都可以使用,避免\\ or /的困扰。
/**
* 递归遍历一个目标及所有子目录下的文件,打印其文件名
* @param dir
*/
public void listDirectory(File dir) {
if(!dir.exists())
throw new IllegalArgumentException("目录" + dir + "不存在");
if(!dir.isDirectory())
throw new IllegalArgumentException(dir + "不是一个目录");
//String[] fileNames = dir.list();
File[] files = dir.listFiles(); //如果要遍历子目录下的内容,就要构造File对象做递归操作
if(files != null && files.length > 0) {
for(File file : files) {
if(file.isDirectory())
listDirectory(file);
else System.out.println(file.getName());
}
} }
三。RandomAccessFile的使用
- Java提供的对文件内容的访问,既可以读文件,也可以写文件。
- 支持随机访问文件,可以访问文件的任意位置。
- Java文件模型:
- 在硬盘上的文件是byte byte byte存储的,是数据的集合。
- 打开文件
- 有两种模式“rw”和“r”
- RandomAccessFile raf = new RandomAccessFile(file, "rw");
- 文件指针,打开文件是指针在开头 pointer = 0;
- 写文件
- raf.write(int) —— 只写一个字节(后8位),同时指针指向下一个位置,准备再次写入
- 读方法
- int b = raf.read() —— 读一个字节
- 文件读写完成后一定要关闭
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
File demo = new File("demo");
if(!demo.exists())
demo.mkdir();
File file = new File(demo, "raf.dat");
if(!file.exists())
file.createNewFile(); RandomAccessFile raf = new RandomAccessFile(file, "rw");
//指针的位置,输出为0,随机读取文件好处:文件下载时,文件很大,分成程序同时下载,灭个下载
//然后在拼接在一起,迅雷每个线程下载文件的一部分,需要知道拼接的位置在哪里,所以需要随机读取
System.out.println(raf.getFilePointer()); raf.write('A'); //只写了一个字节(后8位)
System.out.println(raf.getFilePointer()); int i = 0x7fffffff;
//用write方法,每次只能写一个字节,所以得写4次
raf.write(i >>> 24);
raf.write(i >>> 16);
raf.write(i >>> 8);
raf.write(i);
System.out.println(raf.getFilePointer()); //可以直接写一个int
raf.writeInt(i);
String s = "中";
byte[] utf = s.getBytes("gbk");
raf.write(utf);
System.out.println(raf.getFilePointer()); //读文件,必须把指针移到头部
raf.seek(0);
byte[] buf = new byte[(int)raf.length()];
raf.read(buf);
System.out.println(Arrays.toString(buf));
System.out.println(new String(buf, "utf-8"));
for(byte b : buf) {
System.out.print(Integer.toHexString(b & 0xff) + " ");
} }
四。字节流的使用
- IO流(输入流、输出流; 字节流、字符流)
- InputStream
- 抽象了应用程序读取数据的方式;
- int b = in.read(); //读取一个字节,无符号填充到int的低八位。-1是EOF
- in.read(byte[] buf) //读取数据填充到字符数组buf中
- OutputStream
- 抽象了应用程序写出数据的方式;
- out.write(int b) //只写出一个byte到流,b的低八位
- out.write(byte[] buf) //将buf字节数组都写入到流
- EOF = End 读到-1就读到结尾了
- FileInputStream —— 具体实现了在文件上读取数据
byte类型为8位,int类型为32位,为了避免数据转换错误,通过&0xff 将高位24位清零!
- 批量读取与单独读取有什么区别?用批量读取会节省很多时间。
//批量读取,适合大文件
public static void printHexByByteArray(String fileName) throws IOException {
FileInputStream in = new FileInputStream(fileName);
byte[] buf = new byte[20 * 1024];
int bytes = 0;
int j = 1;
while((bytes = in.read(buf, 0, buf.length)) != -1) {
for(int i=0; i<bytes; i++) {
System.out.print(Integer.toHexString(buf[i] & 0xff) + " ");
if(j++ % 10 == 0)
System.out.println();
}
}
} //单字节读取
/**
* 读取指定文件内容,按照16进制输出到控制台
* 每输出10个byte就换行
* @param fileName
* @throws IOException
*/
public static void printHex(String fileName) throws IOException {
//把文件作为字节流进行读操作
FileInputStream in = new FileInputStream(fileName);
int b;
int i = 0;
while((b = in.read()) != -1) {
if(b <= 0xf)
System.out.print("0");
System.out.print(Integer.toHexString(b) + " ");
if(i++ % 10 == 0)
System.out.println();
}
in.close();
}
- DataInputDtream 和 DataOutputStream
- 对流功能的扩展,可以更加方便的读取int,long,字符等类型数据,如writeInt()/writeDouble()/writeUTF()
- BufferedInoutStream 和 BufferedOutputStream
- 这两个类为IO提供了带缓冲区的操作,一般打开文件进行写入或读取操作时,都会加上缓冲,这种流模式提高了IO的性能
- 从应用程序中把输入放入文件,相当于将一桶水倒入另一个桶中:
- FileOutputStream的write()方法相当于一滴一滴地把水转移过去;
- DataOutputStream的writexxx()方法相当于用一个非常小的容器转移;
- BufferedOutputStream的write()方法相当于用一个更大的容器做缓存,提高性能。
/**
* 通过缓冲区的方法拷贝文件
* @param srcFile
* @param dstFile
* @throws IOException
*/
public static void copyFileByBuffer(File srcFile, File dstFile) throws IOException {
if(!srcFile.exists())
throw new IllegalArgumentException("File: " + srcFile + " not exist.");
if(!srcFile.isFile())
throw new IllegalArgumentException(srcFile + "not a file.");
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(srcFile));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(dstFile));
int c;
while((c = bis.read()) != -1) {
bos.write(c);
bos.flush();
}
bis.close();
bos.close();
}
五。字符流的使用
- 文本和文本文件
- Java中的文本(char)是16位无符号整数,是字符的Unicode编码(双字节编码);
- 文件是byte byte byte的数据序列;
- 文本文件是文本(char)序列按照某种编码方案(utf-8, utf-16be,gbk)序列化为byte的存储。
- 字符流(Reader,Writer)—— 操作的是文本文件
- 字符的处理,一次处理一个字符;
- 字符的底层仍然是基本的字节序列。
- 字符流的基本实现:
- InputStreamReader 完成byte流解析为char流,按照编码解析
- OutputStreamReader 提供char流解析为byte流,按照编码处理
- 文件读写流:
- FileReader
- FileWriter
- 字符流的过滤
- BufferedReader —— 可以readLine,一次读一行
- BufferedWriter/Printer —— 写一行
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream("demo/out.data")));
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream("demo/out1.data")));
PrintWriter pw = new PrintWriter("demo/out2.data");
String line;
while((line = br.readLine()) != null) {
System.out.println(line);
pw.println(line);
pw.flush();
// bw.write(line);
// bw.newLine();
// bw.flush();
}
pw.close();
bw.close();
br.close(); }
六。序列化与反序列化
- 对象的序列化和反序列化
- 对象序列化是指将Object对象转化成byte序列,反之叫做对象的反序列化;
- 序列化流(ObjectOutputStream)是过滤流——writeObject();
- 反序列化流(ObjectInputStream)—— readObject();
- 序列化接口(Serializable)
- 对象必须实现序列化接口才能实现序列化,否则将出现异常,这个接口没有任何方法,只是一个标准。
- 对象的序列化和反序列化将那些实现了Serialization接口的对象转换成一个字节序列,并能够在以后将这个字节完全恢复为原来的对象;
- 这样做的一个好处是:能够自动弥补不同操作系统之间的差异。可以在运行Windows操作系统的计算机上创建一个对象,将其序列化,通过网络将它发送给一台运行Unix系统的计算机,然后在那里能够准确的重新组装,而不必担心数据在不同机器上的表示会不同,也不必关心字节的顺序或者其他任何细节;
- 将序列化的概念加入java中主要是为了支持两种特性:
- 一是java的远程方法调用(Remote Method Invocation,RMI),它使存活在其他计算机上的对象使用起来就像存活于本机上一样,当向远程对象大宋消息时,需要通过对象序列化来传输参数和返回值;
- 二是对于java Bean来说,序列化也是必须的。使用一个Bean时,一般情况是在设计阶段对他的状态信息进行配置。这种状态信息必须保存下来,并在程序启东市进行后期恢复。
public static void main(String[] args) throws IOException, IOException {
String file = "demo/obj.txt";
//1. 对象序列化
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(file));
StudentDemo st = new StudentDemo("aaa", "12", 15);
oos.writeObject(st);
oos.flush();
oos.close(); //2.反序列化
ObjectInputStream pis = new ObjectInputStream(
new FileInputStream(file));
try {
StudentDemo stu = (StudentDemo) pis.readObject();
System.out.println(stu);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
pis.close();
}
- transient 修饰后,不会进行虚拟机默认的序列化;也可以自己完成这个元素的序列化
- 为什么要使用transient关键字呢?
- 分析ArrayList的序列化与反序列化:实质是一个数组,但是这个数组并不一定放满了,因此我们不需要讲后面没有使用的地方进行序列化,可以根据自己的需要定制序列化,只是序列化数组中的有效元素,提高性能。
- 序列化中子父类构造函数调用问题
- 一个类实现了序列化接口,其子类都可以进行序列化
- 对子类对象进行反序列化操作时,如果其父类没有实现序列化接口,那么其父类的构造函数会被调用;反之不会。
Java——再看IO的更多相关文章
- java nio 与io区别
转自:http://blog.csdn.net/keda8997110/article/details/19549493 当学习了Java NIO和IO的API后,一个问题马上涌入脑海: 我应该何时使 ...
- java中的IO操作总结
一.InputStream重用技巧(利用ByteArrayOutputStream) 对同一个InputStream对象进行使用多次. 比如,客户端从服务器获取数据 ,利用HttpURLConnect ...
- Java NIO 和 IO 的区别详解
Java NIO为jdk1.4提供了新的API,本文主要来比较一下Java中NIO和IO的区别,Java初学者可以了解一下. 下表总结了Java NIO和IO之间的主要差别,我会更详细地描述表中每部分 ...
- Java NIO与IO
当学习了Java NIO和IO的API后,一个问题立即涌入脑海: 我应该何时使用IO,何时使用NIO呢?在本文中,我会尽量清晰地解析Java NIO和IO的差异.它们的使用场景,以及它们怎样影响您的代 ...
- Java NIO 与 IO
我应该何时使用 IO,何时使用 NIO 呢?在本文中,我会尽量清晰地解析 Java NIO 和 IO 的差异.它们的使用场景,以及它们如何影响您的代码设计. Java NIO 和 IO 的主要区别 下 ...
- [转载] Java NIO与IO
原文地址:http://tutorials.jenkov.com/java-nio/nio-vs-io.html 作者:Jakob Jenkov 译者:郭蕾 校对:方腾飞 当学习了Java ...
- 从同步阻塞聊到Java三种IO方式
本文总结自 https://zhuanlan.zhihu.com/p/34408883, https://www.zhihu.com/question/19732473中愚抄的回答, http://b ...
- Java 中的 IO 与 socket 编程 [ 复习 ]
一.Unix IO 与 IPC Unix IO:Open-Read or Write-Close IPC:open socket - receive and send to socket - clos ...
- Java NIO系列教程(十二) Java NIO与IO
当学习了Java NIO和IO的API后,一个问题马上涌入脑海: 我应该何时使用IO,何时使用NIO呢?在本文中,我会尽量清晰地解析Java NIO和IO的差异.它们的使用场景,以及它们如何影响您的代 ...
随机推荐
- zw版【转发·台湾nvp系列Delphi例程】HALCON HWindowX 02
zw版[转发·台湾nvp系列Delphi例程]HALCON HWindowX 02 procedure TForm1.Button1Click(Sender: TObject);var img : H ...
- Openstack的error僵尸实例的解决办法
在我们对集群环境进行各种调整的情况下,很容易产生一些僵尸实例. 僵尸实例主要是没有该主机,但是在dashboard上,数据库中存在,解决办法网络上有的人给出了繁杂的修改数据库的方法,其实按照下面的命令 ...
- Office 2007在安装过程中出错-解决办法
1, 可能是因为c:\program files\common files\microsoft Shared\web server Extensions\40\bin目录下缺少Fp4autl.dll, ...
- scala匿名函数
package com.ming.test import scala.math._ object AnonymousFunc { def valueAtOneQuarter(f:(Double)=&g ...
- memcache缓存详解
这篇文章主要介绍了PHP中的Memcache,从Memcache简介开始,详细讲解了如Memcache和memcached的区别.PHP的 Memcache所有操作方法.每个操作方法的详细解释等,需要 ...
- Linux系统中“动态库”和“静态库”那点事儿【转】
转自:http://blog.chinaunix.net/uid-23069658-id-3142046.html 今天我们主要来说说Linux系统下基于动态库(.so)和静态(.a)的程序那些猫腻. ...
- Java常见编码方式简介
计算机只能识别二进制数据,早期由来是电信号. 为了方便应用计算机,让它可以识别各个国家的文字. 就将各个国家的文字用数字来表示,并一一对应,形成一张表. ASCII:美国标准信息交换码. 用一个字节的 ...
- 未知的系统错误(The transaction is no longer active - status: 'Committed'. No further JDBC access is allowed within this transaction.)
被调用接口处理并发能力太脆弱导致的问题. 重新请求下即可.
- POSTGRESQL9.5之pg_rman工具
pg_rman是一款专门为postgresql设计的在线备份恢复的工具.其支持在线和基于时间点备份方式,还可以通过创建backup catalog来维护DB cluster备份信息. 看起来好像是模仿 ...
- jquery ui 常用(一)(自动完成 | 标签页 | 折叠面板 | 带图标的按钮 | 日期选择器| )
条件,引用3个文件 jquery-ui.min.css; jquery.min.js; jquery-ui.min.js. 一.自动完成 http://www.w3cschool.cc/jqueryu ...