一。编码问题

  • 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的更多相关文章

  1. java nio 与io区别

    转自:http://blog.csdn.net/keda8997110/article/details/19549493 当学习了Java NIO和IO的API后,一个问题马上涌入脑海: 我应该何时使 ...

  2. java中的IO操作总结

    一.InputStream重用技巧(利用ByteArrayOutputStream) 对同一个InputStream对象进行使用多次. 比如,客户端从服务器获取数据 ,利用HttpURLConnect ...

  3. Java NIO 和 IO 的区别详解

    Java NIO为jdk1.4提供了新的API,本文主要来比较一下Java中NIO和IO的区别,Java初学者可以了解一下. 下表总结了Java NIO和IO之间的主要差别,我会更详细地描述表中每部分 ...

  4. Java NIO与IO

    当学习了Java NIO和IO的API后,一个问题立即涌入脑海: 我应该何时使用IO,何时使用NIO呢?在本文中,我会尽量清晰地解析Java NIO和IO的差异.它们的使用场景,以及它们怎样影响您的代 ...

  5. Java NIO 与 IO

    我应该何时使用 IO,何时使用 NIO 呢?在本文中,我会尽量清晰地解析 Java NIO 和 IO 的差异.它们的使用场景,以及它们如何影响您的代码设计. Java NIO 和 IO 的主要区别 下 ...

  6. [转载] Java NIO与IO

    原文地址:http://tutorials.jenkov.com/java-nio/nio-vs-io.html 作者:Jakob Jenkov   译者:郭蕾    校对:方腾飞 当学习了Java ...

  7. 从同步阻塞聊到Java三种IO方式

    本文总结自 https://zhuanlan.zhihu.com/p/34408883, https://www.zhihu.com/question/19732473中愚抄的回答, http://b ...

  8. Java 中的 IO 与 socket 编程 [ 复习 ]

    一.Unix IO 与 IPC Unix IO:Open-Read or Write-Close IPC:open socket - receive and send to socket - clos ...

  9. Java NIO系列教程(十二) Java NIO与IO

    当学习了Java NIO和IO的API后,一个问题马上涌入脑海: 我应该何时使用IO,何时使用NIO呢?在本文中,我会尽量清晰地解析Java NIO和IO的差异.它们的使用场景,以及它们如何影响您的代 ...

随机推荐

  1. [OrangePi] If you are using an older image

    Download scriptbin_kernel.tar.gz from Mega, unpack. Copy uImage_OPI-2 or uImage_OPI-PLUS (depending ...

  2. 常用的DC插头公头的尺寸

    2.0*0.6mm:这种应该是用在诺基亚黑白屏那种手机上的充电插头 2.5*0.7mm:这种不知用在哪里 3.5*1.35mm:应该是以前那种小型的磁带机放音机上用的 4.0*1.7mm:已知 ora ...

  3. js调用后台方法(如果你能容忍执行的后台方法变成一个常量)

    最近一直在做一个电话拨号的系统,系统不大,但是做的时间有点长了.其中用到了一个技术:js调用后台方法.解决这个问题花了不少时间,现如今仍然还有些不明白的地方,今天跟大家分享一下.真正明白的同学欢迎指正 ...

  4. Sublime中增加格式化代码的快捷键

    [Preferences]->[Key Bindings]->[User]中,添加如下: { "keys": ["alt+shift+f"], &q ...

  5. 缓存方案之Redis

    Redis简介   Redis是Remote Dictionary Server(Redis) 的缩写,或许光听名字你就能猜出它大概是做什么的.不错,它是一个由Salvatore Sanfilippo ...

  6. 程序员PC选购

    程序员PC选购[转载] http://www.cnblogs.com/legendtao/p/4631150.html 好马配上好鞍,自然事半功倍.一台好的PC能给你更好的工作娱乐体验~~(卧槽,感觉 ...

  7. Volley的基本用法

    1. Volley简介 我们平时在开发Android应用的时候不可避免地都需要用到网络技术,而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据.Android系统中主要提供了两种方式来进行H ...

  8. Java 中日期的几种常见操作 —— 取值、转换、加减、比较

    Java 的开发过程中免不了与 Date 类型纠缠,准备总结一下项目经常使用的日期相关操作,JDK 版本 1.7,如果能够帮助大家节约那么几分钟起身活动一下,去泡杯咖啡,便是极好的,嘿嘿.当然,我只提 ...

  9. ACM题目————Team Queue

    Queues and Priority Queues are data structures which are known to most computer scientists. The Team ...

  10. CI框架分页类

    分页类1.分页类参数说明 'base_url' => 指向你的分页所在的控制器类/方法的完整的 URL, 'total_rows' => 数据的总行数, 'per_page' => ...