了解
- 文件的编码
- File类的使用
- RandomAccessFile类的使用
- 字节流
- 字符流
- 对象的序列化和反序列化
文件的编码
有时候我们打开一个文件或者是网页发现里面出现的都是乱码。其原因是编辑文件时所采用的编码方法和打开文件时所采用的解码方式不同,所以造成打开文件看到的都是乱码。
在Java中,GBK编码中文占用2个字节,英文占用1个字节,UTF-8编码中,中文占用3个字节,英文占用1个字节。
范例
import java.io.UnsupportedEncodingException;
/**
* Created by 99479 on 2017/7/11.
*/
public class EncodeDemo01 {
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "蒲杰ABC";
byte [] bytes = s.getBytes("gbk");//转换成字节序列,用的是项目默认的编码
for (byte b:
bytes) {
//把字节(转换了int)以16进制的方式显示
System.out.print (Integer.toHexString(b & 0xff)+" ");
}
System.out.println();
for (byte b:
s.getBytes("utf-8")) {
System.out.print(Integer.toHexString(b & 0xff)+" ");
}
System.out.println();
/**
* 当你的字节序列是某种编码时,这个时候想把字节序列变成字符串,也需要用这种编码方式,否者会出现乱码
*/
String s1 = new String(bytes);//用项目的默认编码
System.out.println(s1); //输出乱码
String s2 = new String(bytes,"gbk");
System.out.println(s2);
/**
* 文本文件 就是字节序列
* 可以是任意编码的字节序列
* 入股我们在中文机器机器上直接创建文本文件,那么该文本文件只认识snsi编码
*/
}
}
输出
c6 d1 bd dc 41 42 43
e8 92 b2 e6 9d b0 41 42 43
�ѽ�ABC
蒲杰ABC
File类的使用##
在Java中,File类用于表示文件或者表示目录。在java.io.File包中。File类只用于表示文件(目录)的信息(名称、大小等),不能用于文件内容的访问。下面的范例都演示File类的基本操作。
范例1,常用API
import java.io.File;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/11.
*/
public class FileDemo {
public static void main(String[] args) {
//了解构造函数
File file = new File("d:"+File.separator+"javaio");
//查看文件是否存在
System.out.println(file.getName()+" 是否存在:" +file.exists());
//如果不存在就创建此文件夹,存在就删除此文件
if(!file.exists()){
file.mkdir();//创建文件夹
//判断是否时一个目录
System.out.println(file.getName()+" 是否是一个文件夹:" + file.isDirectory());
//判断是否时一个文件
System.out.println(file.getName()+" 是否是一个文件:" + file.isFile());
}else {
boolean isDelete = file.delete();
System.out.println(file.getName()+" 是否删除成功:" + isDelete);
}
//创建一个文件对象
File file1 = new File("d:"+File.separator+"日记.txt");
System.out.println(file1.getName() + " 文件是否存在:" + file1.exists());
if (!file1.exists()){
try {
boolean isCreat = file1.createNewFile();
System.out.println(file1.getName()+" 是否创建成功:"+ isCreat);
System.out.println(file1.getName()+" 是否是一个文件夹:" + file1.isDirectory());
System.out.println(file1.getName()+" 是否是一个文件:" + file.isFile());
System.out.println(file1.getName()+" 的绝对路径:" + file1.getAbsolutePath());
System.out.println(file1.getName()+" 的父路径:" + file1.getParent());
} catch (IOException e) {
e.printStackTrace();
}
}else {
boolean isDelete = file1.delete();
System.out.println(file1.getName()+" 是否删除成功:"+ isDelete);
}
}
}
输出
javaio 是否存在:true
javaio 是否删除成功:true
日记.txt 文件是否存在:false
日记.txt 是否创建成功:true
日记.txt 是否是一个文件夹:false
日记.txt 是否是一个文件:false
日记.txt 的绝对路径:d:\日记.txt
日记.txt 的父路径:d:\
范例2,遍历目录
FileUtil.java
import java.io.File;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/12.
* 列出File的一些常用操作比如过滤、遍历等操作
*/
public class FileUtils {
/**
* 列出某个目录的所有文件或者包括子目录中的所有文件和文件夹
* @param dir
* @throws IOException
*/
public static void listDirectory(File dir) throws IOException{
if (!dir.exists()){
throw new IllegalArgumentException("目录:"+dir+"不存在");
}
if (!dir.isDirectory()){
throw new IllegalArgumentException(dir+"不是目录");
}
String [] filenames = dir.list();
File[] files = dir.listFiles();
for (File file: files) {
if (file.isFile()){
System.out.println("文件: "+file.getAbsolutePath());
}else if (file.isDirectory()){
System.out.println("文件夹:"+file.getAbsolutePath());
//递归调用
listDirectory(file);
}
}
}
}
FileUtilTest01.java
import java.io.File;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/12.
*/
public class FileUtilsTest01 {
public static void main(String[] args) {
try {
FileUtils.listDirectory(new File("D:"+File.separator+"迅雷下载"+File.separator+"杀不死"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出
文件夹:D:\迅雷下载\杀不死\test
文件: D:\迅雷下载\杀不死\test\0.0.txt
文件夹:D:\迅雷下载\杀不死\test\新建文件夹
文件: D:\迅雷下载\杀不死\test\新建文件夹\tstsbg.txt
文件: D:\迅雷下载\杀不死\[杀BS]第01集_bd.mp4
文件: D:\迅雷下载\杀不死\[杀BS]第02集_bd.mp4
文件: D:\迅雷下载\杀不死\[杀BS]第03集_bd.mp4
文件: D:\迅雷下载\杀不死\[杀BS]第04集_bd.mp4
文件: D:\迅雷下载\杀不死\[杀BS]第05集_bd.mp4
文件: D:\迅雷下载\杀不死\[杀BS]第06集_bd.mp4
文件: D:\迅雷下载\杀不死\[杀BS]第07集_bd.mp4
文件: D:\迅雷下载\杀不死\[杀BS]第08集_bd.mp4
文件: D:\迅雷下载\杀不死\[杀BS]第09集_bd.mp4
文件: D:\迅雷下载\杀不死\[杀BS]第10集_bd.mp4
文件: D:\迅雷下载\杀不死\[杀BS]第11集_bd.mp4
文件: D:\迅雷下载\杀不死\[杀BS]第12集_bd.mp4
RandomAccessFile基本操作
RandomAccessFile时Java提供的对文件内容的访问类,既可以读文件,也可以写文件。RandomAccessFile支持随机访问文件,可以访问文件的任意位置
(1)Java的文件模型,
在硬盘上的文件是以byte byte byte存储的,时数据的集合。
(2)打开文件有两种模式
1、“rw”读写。2、“r”只读。
在使用RandomAccessFile操作文件的时候不仅要传入要操作文件的路径,还要传入操作文件的方式,例:RandomAccessFile raf = new RandomAccessFile("file","rw");
由于是随机访问文件,它包含一个文件指针,打开文件时指针在开头 pointer = 0;
(3)、写方法
raf.write(int) ---> 只写一个字节(后8位),同时指针指向下一个位置,准备再次写入。
(4)、读方法
int b = raf.read() ---> 读一个字节
(5)、文件读写完成后一定要关闭(Oracle官方说明),以防出现意想不到的错误。
范例
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
/**
* Created by 99479 on 2017/7/12.
*/
public class RafDemo {
public static void main(String[] args) throws IOException {
File demo = new File("demo");
if (!demo.exists()){
demo.mkdir();
}
//以demo为父目录
File file = new File(demo,"raf.dat");
if (!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println(file.getAbsolutePath());
RandomAccessFile raf = new RandomAccessFile(file,"rw");
//指针的位置
System.out.println("指针的位置"+raf.getFilePointer());
System.out.println("开始写文件...");
raf.write('A');//只写了一个字节
System.out.println("指针的位置"+raf.getFilePointer());
raf.write('B');
int i=0x7fffffff;
//用write方法每次只写一个字节,如果要把i写进去就得写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 [] gbk = s.getBytes("gbk");
raf.write(gbk);
System.out.println("文件的长度: "+raf.length());
System.out.println("开始读文件...");
//读文件,必须把指针移到头部
raf.seek(0);
//一次性读取,把文件中的内容都读到字节数组中
byte [] buf = new byte[(int)(raf.length())];
raf.read(buf);
System.out.println(Arrays.toString(buf));
//关闭文件操作流
raf.close();
}
}
输出
D:\IdeaProjects\TestDemo\demo\raf.dat
指针的位置0
开始写文件...
指针的位置1
指针的位置6
文件的长度: 12
开始读文件...
[65, 66, 127, -1, -1, -1, 127, -1, -1, -1, -42, -48]
首先要了解流的概念,在Java中IO流就是输入输出流,在这里面也分为了字节流、字符流。
字节流##
(1)字节流又分为InputStream、OutputStream两个抽象类
InputStream:抽象了应用程序读取数据的方式。
OutputStream:抽象了应用程序写出数据的方式。
(2)读到返回值为-1就表示已经读到结尾。
(3)字节输入流基本方法:
- int b = in.read();读取一个字节无符号填充到int低八位。读到-1结束
- in.read(byte [] buf)读取数据填充到字节数组
- in.read(byte [] buf,int start,int size)读取数据填充到字节数组buf,从buf的start位置开始存放size长度的数据。
(4)字节输出流的基本方法:
- out.write(int b)写出一个byte到流,b的低八位
- out.write(byte [] buf)将buf字节数据都写入到流
- out.write(byte [] buf,int start,int size)字节数组buf从start位置开始写size长度的字节流。
了解
- 字节流之文件输入流FileInputStream
- 字节流之文件输出流FileOutputStream
- 字节流之数据输入输出流
- 字节缓冲流
字节流之文件输入流FileInputStream
FileInputStream继承了抽象类InputStream。具体实现了在文件上读取数据。
范例
IOUtil
import java.io.FileInputStream;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/13.
*/
public class IOUtil {
/**
* 读取指定文件内容,按照16进制输出到控制台
* 并且每输出10个byte就换行
* @param fileName
*/
public static void printHex(String fileName) throws IOException{
//把文件作为字节流进行读操作
FileInputStream in = new FileInputStream(fileName);
int b;
int i = 1;
while((b = in.read()) != -1){
System.out.print(Integer.toHexString(b)+" ");
if (i++%10 == 0){
System.out.println();
}
}
//关闭输入流
in.close();
}
public static void printHexByByteArray(String fileName)throws IOException{
FileInputStream in = new FileInputStream(fileName);
byte [] buf = new byte[20*1024];
//从in中批量读取字节,放入到buf这个字节数组中,
// 从第0个位置开始放,最多放buf.length个,
//返回的是读到的字节的个数
int bytes = in.read(buf,0,buf.length);//一次性读完,说明字节数组足够大
int j = 1;
for (int i = 0 ; i < bytes ; i++){
if (buf[i] <= 0xf){
System.out.print("0");
}
System.out.print(Integer.toHexString(buf[i])+" ");
if (j++%10 == 0){
System.out.println();
}
}
}
}
IOUtilTest01
import java.io.IOException;
/**
* Created by 99479 on 2017/7/13.
*/
public class IOUtilTest01 {
public static void main(String[] args) {
try {
IOUtil.printHex("D:\\IdeaProjects\\TestDemo\\demo\\raf.dat");
} catch (IOException e) {
e.printStackTrace();
}
}
}
IOUtilTest02
import java.io.IOException;
/**
* Created by 99479 on 2017/7/13.
*/
public class IOUtilTest02 {
public static void main(String[] args) {
try {
IOUtil.printHexByByteArray("D:\\IdeaProjects\\TestDemo\\demo\\raf.dat");
} catch (IOException e) {
e.printStackTrace();
}
}
}
字节流之文件输出流FileOutputStream
FileOutputStream实现了向文件中写出byte数据的方法,继承了OutputStream。
范例
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/13.
*/
public class FileOutDemo01 {
public static void main(String[] args) throws IOException {
//如果文件不存在,则直接创建,如果存在,删除后创建
FileOutputStream out = new FileOutputStream("D:\\IdeaProjects\\TestDemo\\demo\\raf.dat");
//如果是追加内容,则使用
// FileOutputStream out = new FileOutputStream("D:\\IdeaProjects\\TestDemo\\demo\\raf.dat",true);
out.write('A');//写出了A的低八位
out.write('B');//写出了'B'的低八位
int a = 10;//write只能写八位,那么写一个int需要写4次每次8位
out.write(a >>> 24);
out.write(a >>> 16);
out.write(a >>> 8);
out.write(a);
byte[] gbk = "中国".getBytes("gbk");
out.write(gbk);
out.close();
IOUtil.printHex("D:\\IdeaProjects\\TestDemo\\demo\\raf.dat");
}
}
输出
41 42 0 0 0 a d6 d0 b9 fa
范例:利用文件输入流、文件输出流实现文件的拷贝
IOUtil
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/13.
*/
public class IOUtil {
/**
* 读取指定文件内容,按照16进制输出到控制台
* 并且每输出10个byte就换行
* @param fileName
*/
public static void printHex(String fileName) throws IOException{
//把文件作为字节流进行读操作
FileInputStream in = new FileInputStream(fileName);
int b;
int i = 1;
while((b = in.read()) != -1){
System.out.print(Integer.toHexString(b)+" ");
if (i++%10 == 0){
System.out.println();
}
}
//关闭输入流
in.close();
}
public static void printHexByByteArray(String fileName)throws IOException{
FileInputStream in = new FileInputStream(fileName);
byte [] buf = new byte[20*1024];
//从in中批量读取字节,放入到buf这个字节数组中,
// 从第0个位置开始放,最多放buf.length个,
//返回的是读到的字节的个数
int bytes = in.read(buf,0,buf.length);//一次性读完,说明字节数组足够大
int j = 1;
for (int i = 0 ; i < bytes ; i++){
if (buf[i] <= 0xf){
System.out.print("0");
}
System.out.print(Integer.toHexString(buf[i])+" ");
if (j++%10 == 0){
System.out.println();
}
}
}
public static void copyFile(File srcFile,File desFile) throws IOException{
if (!srcFile.exists()){
throw new IllegalArgumentException("文件不存在");
}
if (!srcFile.isFile()){
throw new IllegalArgumentException(srcFile+"不是文件");
}
FileInputStream in = new FileInputStream(srcFile);//读操作
FileOutputStream out = new FileOutputStream(desFile);//写操作
byte [] buf = new byte[8];
int b = 0 ;
while(b != -1){
b = in.read(buf,0,buf.length);
System.out.print(b+" ");
out.write(buf,0,buf.length);
out.flush();//最好加上
}
in.close();
out.close();
}
}
IOUtilTest03
import java.io.File;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/13.
*/
public class IOUtilTest03 {
public static void main(String[] args) {
try {
IOUtil.copyFile(new File("D:\\IdeaProjects\\TestDemo\\demo\\raf.dat"),new File("D:\\IdeaProjects\\TestDemo\\demo\\NEWraf.txt"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出
8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 3 -1
字节流之数据输入输出流DataOutputString/DataInputStream
这一组操作类是对“流”的扩展,可以更加方便的读取int,long/字符等类型数据。
DataOutputString中的方法举例:writeInt() 、 writeDouble() 、writeUTF()
范例:DataOutputStream
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/19.
* 往一个文件里面写数字,或者写普通的数据类型
*/
public class DosDemo {
public static void main(String[] args) throws IOException{
String file = "demo/dos.dat";
DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
dos.writeInt(10);
dos.writeInt(-10);
dos.writeLong(10l);
dos.writeDouble(10.5);
//采用UTF-8编码写出
dos.writeUTF("中国");
//采用UTF-16BE编码写出
dos.writeChars("中国");
dos.close();
IOUtil.printHex(file);
}
}
输出
0 0 0 a ff ff ff f6 0 0
0 0 0 0 0 a 40 25 0 0
0 0 0 0 0 6 e4 b8 ad e5
9b bd 4e 2d 56 fd
范例:DataInputStream
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/19.
*/
public class DisDemo {
public static void main(String[] args) throws IOException{
String file = "demo/dos.dat";
IOUtil.printHex(file);
DataInputStream dis = new DataInputStream(new FileInputStream(file));
int i = dis.readInt();
System.out.println(i);
i = dis.readInt();
System.out.println(i);
long l = dis.readLong();
System.out.println(l);
double d = dis.readDouble();
System.out.println(d);
String s = dis.readUTF();
System.out.println(s);
dis.close();
}
}
输出
0 0 0 a ff ff ff f6 0 0
0 0 0 0 0 a 40 25 0 0
0 0 0 0 0 6 e4 b8 ad e5
9b bd 4e 2d 56 fd 10
-10
10
10.5
中国
字节缓冲流
字节缓冲流主要学习了解BufferedInputStream和BuferedOutputStream
这两个流类为IO提供了带缓冲区的操作,一般打开文件进行写入或读取操作时,都会加上缓冲,这种流模式主要提高了IO的输入输出性能。
从应用程序中把数据输入放入文件,相当于将一缸水倒入到另一个缸中,其中:
FileOutputStream ---> write()方法相当于一滴一滴地把水“转移”过去。
DataOutputStream ---> writeXxx()方法会方便一些,相当于一瓢一瓢的把水“转移”过去。
BufferedOutputStream ---> write()方法更方便,相当于一瓢一瓢先放入桶中,再从桶中倒入到另一个缸中,提高了性能。
范例:修改IOUtil.java
增加方法:copyFileByBuffer
/**
* 进行文件的拷贝,使用带缓冲的字节流
* @param srcFile
* @param destFile
* @throws IOException
*/
public static void copyFileByBuffer(File srcFile,File destFile)throws IOException{
if (!srcFile.exists()){
throw new IllegalArgumentException("文件不存在");
}
if (!srcFile.isFile()){
throw new IllegalArgumentException(srcFile+"不是文件");
}
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));
int c ;
while((c = bis.read()) != -1){
bos.write(c);
bos.flush();//刷新缓冲区
}
bis.close();
bos.close();
}
范例:IOUtilTest04
import java.io.File;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/19.
*/
public class IOUtilTest04 {
public static void main(String[] args) throws IOException {
IOUtil.copyFileByBuffer(new File("D:\\test.txt"),new File("D:\\test\\new_test.txt"));
}
}
输出
之前的:
之后的:
字符流
字符流操作文本文件,如果是MP3,图片,视频之类的文件都采用字节流。
字符流的基本概念:
- 编码问题
- 认识文本和文本文件:Java的文本(char)是16位无符号整数,是字符的unicode编码(双字节编码)。文件是byte byte byte...的序列,文本文件是文本(char)序列按照某种编码方案(utf-8、utf-16be、gbk)序列化为byte的存储结构。
- 在Java里面的字符流也有读(Reader抽象类),写(Writer抽象类),字符的处理,一次处理一个字符,字符的底层仍然是基本的字节序列。
- Java中字符流的基本条件:
InputStreamReader 完成byte流解析为char流,按照编码解析。
OutputStreamWriter 提供char流到byte流,按照编码处理。
范例:对一个文件进行简单的读操作
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* Created by 99479 on 2017/7/20.
*/
public class IsrAndAOswDemo {
public static void main(String[] args) throws IOException{
FileInputStream in = new FileInputStream("D:\\test.txt");
InputStreamReader isr = new InputStreamReader(in,"utf-8");//项目的默认编码
// int c ;
// while((c = isr.read()) != -1){
// System.out.print((char)c);
// }
char [] buffer = new char[8*1024];
int c;
//批量读取,放入buffer这个字符数组,从第0个位置开始方式,最多放buffrt.length个
//返回的是读到的个数
StringBuffer stringBuffer = new StringBuffer();
while ((c = isr.read(buffer,0,buffer.length)) != -1){
stringBuffer.append(buffer,0,buffer.length);
}
System.out.println(stringBuffer);
isr.close();//一定要注意关闭,注意关闭,注意关闭
}
}
输出
客家话和;oh;一; 可不行了就回北京了黑戈壁厉害个i好吧;;iuh
;和哦哦哦回家oh;和
字符流的基本概念:
1. 编码问题
- 认识文本和文本文
字符流的另一组操作类:
写文件:FileWriter
写文件:FileReader
刚刚做的字符流的读写操作类(InputStreamReader、OutputStreamReader)使用时嵌套了一个类,如果使用FileWriter、FileReader就很方便了。
范例:做读写操作
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
* Created by 99479 on 2017/7/20.
*/
public class FrAndFwDemo {
public static void main(String[] args) throws IOException{
FileReader fr = new FileReader("D:\\test.txt");
FileWriter fw = new FileWriter("D:\\test\\new_test.txt");
char [] buffer = new char[1024];
int c;
while((c = fr.read(buffer,0,buffer.length)) != -1){
fw.write(buffer,0,buffer.length);
fw.flush();
}
//注意关闭,注意关闭,注意关闭
fr.close();
fw.close();
}
}
字符流的过滤器
我们可以对字符流加过滤器,让字符流有更多的功能,常用的有一组:
BufferedReader,它最强大的功能有一个是 ---> readLine 一次读一行。
BufferedWriter/PrintWriter: ---> 写一行。
范例:
import java.io.*;
/**
* Created by 99479 on 2017/7/20.
*/
public class BrAndBwOrPwDemo {
public static void main(String[] args) throws IOException{
//对文件进行读写操作
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("D:\\test.txt")));
// BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\test\\new_test.txt")));
PrintWriter pw = new PrintWriter("D:\\test\\new_test.txt");
String line;
while((line = br.readLine()) != null){//读一行
System.out.println(line);//一次读一行,并不能识别换行
// bw.write(line);
// bw.newLine();//换行操作
// bw.flush();
pw.println(line);
pw.flush();
}
br.close();
// bw.close();
pw.close();
}
}