1. 编码问题
从一种形式或格式转换为另一种形式的过程也称为计算机编程语言的代码简称编码
。而这个转换的方式就是编码方式。
将字符串“例子ABC”分别以gbk
、utf-8
、utf-16be
编码方式转化成字节,如下:
public class Coding {
public static void printByEncoding(String s, String encoding){
try {
byte[] bytes = s.getBytes(encoding);
System.out.print("encoding " + encoding + " : ");
for (byte b : bytes) {
//把字节(转换成了int)以16进制的方式显示
System.out.print(Integer.toHexString(b & 0xff) + " ");
}
System.out.println();
}catch (UnsupportedEncodingException e){
System.out.println("unsupportded encoding: " + encoding);
}
}
public static void main(String[] args) {
String s = "例子ABC";
//gbk编码:中文两个字节,英文一个字节
Coding.printByEncoding(s, "gbk");
//utf-8编码:中文三个字节,英文一个字节
Coding.printByEncoding(s, "utf-8");
// utf-16be编码,中文两个字节,英文两个字节
Coding.printByEncoding(s, "utf-16be");
}
输出结果为:
encoding gbk : c0 fd d7 d3 41 42 43
encoding utf-8 : e4 be 8b e5 ad 90 41 42 43
encoding utf-16be : 4f 8b 5b 50 0 41 0 42 0 43
当你的字节序列是某种编码时,这时候想把字节序列变成字符串,也需要这种编码方式,否则会出现乱码
try {
String str1 = new String(s.getBytes("utf-16be"));
System.out.println(str1);
String str2 = new String(s.getBytes("utf-16be"), "utf-16be");
System.out.println(str2);
}catch (UnsupportedEncodingException e){
System.out.println("unsupportded encoding: " );
}
输出结果为:
O�[P A B C
例子ABC
文本文件就是字节序列,它可以是任何编码的字节序列。
2. File类
java.io.File
类用于表示文件(目录)。File类只用于表示文件(目录)的信息(名称、大小),不能用于文件内容的访问。
File file1 = new File("文件/目录路径");
File file2 = new File(File parent, String child);
File file3 = new File(String parent, String child)
方法 | 描述 |
---|---|
boolean exists() | 判断文件/目录 是否存在 |
boolean mkdir() | 创建目录 |
void createNewFile() | 创建目录 |
delete() | 删除文件/目录 |
boolean isDirectory() | 是否是一个目录,如果不是目录or目录不存在返回false |
boolean isFile() | 是否是一个文件 |
String getName() | 返回文件/目录名。 |
String getAbsolutePath() | 返回抽象路径名的绝对路径名字符串。 |
String getParent() / File getParentFile() | 获取父路径 |
long lastModified() | 返回此抽象路径名表示的文件最后一次被修改的时间。 |
String[] list() | 返回由包含在目录中的文件和目录的名称所组成的字符串数组 |
File[] listFiles() | 返回一个抽象路径名数组,这些路径名表示此抽象路径名所表示目录中的文件。 |
...... | ...... |
eg:遍历目录
package com.company;
import java.io.File;
import java.util.Stack;
/**
* FileItem表示 文件和文件在第几层
*/
public class FileItem {
public File file;
public int depth ;
public FileItem(File file, int depth) {
this.file = file;
this.depth = depth;
}
//遍历文件or目录
public static void printFiles(String path){
//用于存放待访问的节点
Stack<FileItem> stack = new Stack<FileItem>();
//根节点入栈
stack.push( new FileItem(new File("F:\\study"), 0) );
while(!stack.empty() ) {
FileItem item = stack.pop();
File file = item.file;
int depth = item.depth;
//打出文件名,按层数缩进
System.out.println(new String(" ".repeat(2*depth) + file.getName()) );
if(file.exists() && file.isDirectory()){
//遍历下一层
File[] fileList = file.listFiles();
for(File it: fileList){
//下一层入栈
stack.push( new FileItem(it, depth+1) );
}
}
}
}
public static void main(String[] args) {
printFiles("F://");
}
}
3. RandomAccessFile
RandomAccessFile是Java提供的对文件内容的访问,既可以读文件,也可以写文件。
RandomAccessFile支持随机访问文件,即可以访问文件的任意位置。
- (1) java文件模型
在硬盘上的文件是bye bye bye存储的,是数据的集合。 - (2) 打开文件
打开文件时,可以选择两种模式:“rw"(读写),"r"(只读)。
RandomAccessFile raf = new RandomAccessFile(file, "rw");
由于RandomAccessFile支持随机访问文件,需要一个文件指针来指定位置。打开文件时指针在开题pointer = 0;
- (3) 写方法
raf.write(int) //只写一个字节,同时指针指向下一个位置。
- (4) 读方法
int b = raf.read(); //读一个字节
- (5) 文件读写完成后一定要关闭。
4. 字节流
4.1 InputStream和OutputStream
InputStream 和 OutputStream为各种输入输出字节流的基类,所有字节流都继承这两个基类。而且InputStream 和 OutputStream为抽象类
,不进行具体的实现。
InputStream抽象了应用程序读取数据的方式。
OutputStream抽象了应用程序写出数据的方式。
- 输入流常用方法
方法名 | 描述 |
---|---|
int read() throws IOException | 读取一个字节无符号填充到int低八位,-1是EOF |
int read( byte[] buf ) throws IOException | 读取数据填充到字节数组buf |
int read(byte[] buf, int start, int size) throws IOException | /读取数据填充到字节数组buf |
void close() throws IOException | 关闭输入流 |
- 输出流基本方法
方法名 | 描述 |
---|---|
void write(int b) throws IOException | 写出一个byte到流,b的低八位 |
void write( byte[] buf ) throws IOException | 将buf字节数组都写入到流 |
void write(byte[] buf, int start, int size) throws IOException | 将buf字节数组都写入到流 |
void close() throws IOException | 关闭输出流 |
4.2 FileInputStream和FileOutputStream
FileInputStream具体实现了在文件上读取数据。
FileOutputStream具体实现了将byte数据写入文件.
- 读取文件
/**
* 通过int读取指定文件内容,按照16进制输出到控制台
*/
public static void printHexByInt(String filename) throws IOException{
//把文件作为字节流进行读操作
FileInputStream in = new FileInputStream(filename);
int b;
while ( (b=in.read()) != -1 ){
System.out.print(Integer.toHexString(b) + " ");
}
in.close();
}
/**
* 通过byte读取指定文件内容,按照16进制输出到控制台
*/
public static void printHexByBytes(String filename) throws IOException{
//把文件作为字节流进行读操作
FileInputStream in = new FileInputStream(filename);
byte[] buf = new byte[1024]; //随便大小都可,大一点可能更快
//从in中批量读取字节, 最多读取 buf.length个,返回读到的数据的个数
//int bytes = in.read(buf);
int bytes = 0;
while ( ( bytes = in.read(buf) ) != -1){
for(int i = 0; i < bytes; i++){
System.out.print( Integer.toHexString(buf[i] &0x00ff)+ " ");
}
}
}
- 写入文件
//如果该文件不存在,则直接创建;如果存在,删除后创建
FileOutputStream out = new FileOutputStream("out.dat");
//如果该文件不存在,则直接创建;如果存在,在后面继续写
FileOutputStream out2 = new FileOutputStream("out2.dat",true);
out.write('A'); //写出了‘A’的低八位
//write只能写八位,那么写一个int需要4次每次8位
int a = 10;
out.write(a >>> 24);
out.write(a >>> 16);
out.write(a >>> 8 );
out.write(a );
//写入byte数组
byte [] gbk = "中国".getBytes("gbk");
out.write(gbk);
out.close();
- 拷贝一个文件
try {
InputStream in = new FileInputStream("a.txt");
OutputStream out = new FileOutputStream("b.txt");
byte[] buf = new byte[1024];
int bytes;
while( (bytes = in.read(buf)) != -1){
out.write(buf);
out.flush();
}
in.close();
out.close();
}catch (FileNotFoundException e1){
e1.printStackTrace();
}catch (IOException e2){
e2.printStackTrace();
}
4.3 DataInputStream和DataOutputStream
对"流"功能的扩展,可以更加方便地读取int、long、字符等类型数据。
- DataInputStream: readByte()/readInt() / readDouble() / readUTF()...
- DataOutputStream:writeByte()/writeInt() / writeDouble() / writeUTF()...
4.2 字节缓冲流BufferedInputStream和BufferedOutputStream
为IO提供了带缓冲区的操作,一般打开文件进行写入或读取操作时,都会加上缓冲,这种流模式提高了IO的性能。
从应用程序中把输入放入文件,相当于将一缸水倒入到另一缸水中:
- FileOutputStream --> write()方法相当于一滴一滴地把水转移过去
- DataOutputStream->writeXxx()方法会方便点,相当于一瓢一瓢地将水转移过去。
- BufferedOutputStream-->write方法更方便,相当于一瓢一瓢先放入桶中,再从桶中倒入缸中。
拷贝文件:
try {
BufferedInputStream is = new BufferedInputStream(new FileInputStream("a.txt"));
BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream("b.txt"));
int c;
while( (c=is.read())!= -1){
os.write(c);
os.flush(); //刷新缓存区
}
is.close();
os.close();
}catch (FileNotFoundException e1){
e1.printStackTrace();
}catch (IOException e2){
e2.printStackTrace();
}
5. 字符流Reader/Writer
5.1 文本文件
- java的文本(char)是16位无符号整数,是字符的unicode编码(双字节编码)。
- 文件是 byte byte byte...的数据序列。
- 文本文件是文本(char)序列按照某种编码方案(utf-8,utf-16be,gbk) 序列号为byte 的存储结构。
字符的处理,一次处理一个字符。但是字符的底层任然是基本的字节序列 。
5.2 InputStreamReader和OutputStreamWriter
InputStreamReader 完成byte流解析为char流,按照编码解析。
OutputStreamWriter 提供char流到byte流,按照编码处理。
try {
FileInputStream is = new FileInputStream("a.txt");
InputStreamReader isr = new InputStreamReader(is,"gbk");//默认为gbk
//第一种方法
int c;
while( (c = isr.read()) != -1){
System.out.println( (char)c);
}
//第二种方法
char[] buffer = new char[1024];
int n;
while( (n = isr.read(buffer)) !=-1 ){
String s = new String(buffer, 0, n);
System.out.println( s );
}
is.close();
isr.close();
}catch (FileNotFoundException e1){
e1.printStackTrace();
}catch (IOException e2){
e2.printStackTrace();
}
5.3 BufferedReader / BufferedWriter
- BufferedReader : readLine 一次第一行
- BufferedWriter/PrintWriter:写一行
6.对象的序列化和反序列化
对象序列化,就是将Object转换成byte序列,反之叫对象的反序列化 。
- 序列化流(ObjectOutputStream),是过滤流。--- writeObject
- 反序列化流(ObjectInputStream) --- readObject
对象必须实现序列化接口Serializable
,才能序列化,否则将会出现异常。
- 序列化:
public class Student implements Serializable {
private String stuno;
private String stuname;
private int stuage;
public Student(String stuno, String stuname, int stuage) {
this.stuno = stuno;
this.stuname = stuname;
this.stuage = stuage;
}
- 将Object写入文件
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
Student stu = new Student("10000","loserwang",20);
oos.writeObject(stu);
oos.flush();
oos.close();
- 从文件中读取Object
String file = "obj.txt";
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
Student s = (Student) ois.readObject();
System.out.println(s);
添加transient
该元素不会被JVM默认序列化
private transient int name;