欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java IO流 文件传输基础

程序员文章站 2024-03-13 12:23:21
一、文件的编码 package com.study.io; /** * 测试文件编码 */ public class encodedemo { /*...

一、文件的编码

package com.study.io;
/**
* 测试文件编码
*/
public class encodedemo {
/**
* @param args
* @throws exception 
*/
public static void main(string[] args) throws exception {
string s="好好学习abc";
byte[] bytes1=s.getbytes();//这是把字符串转换成字符数组,转换成的字节序列用的是项目默认的编码(这里为utf-8)
for (byte b : bytes1) {
//把字节(转换成了int)以16进制的方式显示
system.out.print(integer.tohexstring(b & 0xff)+" ");//& 0xff是为了把前面的24个0去掉只留下后八位
}
system.out.println();
/*utf-8编码中中文占用3个字节,英文占用1个字节*/
byte[] bytes2 = s.getbytes("utf-8");//这里会有异常展示,我们就throw这个异常
for (byte b : bytes2) {
system.out.print(integer.tohexstring(b & 0xff)+" ");
}
system.out.println();
/*gbk编码中文占用2个字节,英文占用1个字节*/
byte[] bytes3 = s.getbytes("gbk");//这里会有异常展示,我们就throw这个异常
for (byte b : bytes3) {
system.out.print(integer.tohexstring(b & 0xff)+" ");
}
system.out.println();
/*utf-16be编码中文占用2个字节,英文占用2个字节*/
byte[] bytes4 = s.getbytes("utf-16be");//这里会有异常展示,我们就throw这个异常
for (byte b : bytes4) {
system.out.print(integer.tohexstring(b & 0xff)+" ");
}
system.out.println();
/*当你的字节序列是某种编码时,这个时候想把字节序列变成字符串,也需要用这种编码方式,否则会出现乱码*/
string str1=new string(bytes4);//这时会使用项目默认的编码来转换,可能出现乱码
system.out.println(str1);
//要使用字节序列的编码来进行转换
string str2=new string(bytes4,"utf-16be");
system.out.println(str2);
}
}

分析:

* 1. “& 0xff”的解释:
* 0xff表示的是16进制(十进制是255),表示为二进制就是“11111111”。
* 那么&符表示的是按位数进行与(同为1的时候返回1,否则返回0)

* 2.字节byte与int类型转换:
* integer.tohexstring(b & 0xff)这里先把byte类型的b和0xff进行了运算,然后integer.tohexstring取得了十六进制字符串
* 可以看出b & 0xff运算后得出的仍然是个int,那么为何要和 0xff进行与运算呢?直接 integer.tohexstring(b);,将byte强转为int不行吗?答案是不行的.
* 其原因在于:1.byte的大小为8bits而int的大小为32bits;2.java的二进制采用的是补码形式
* integer.tohexstring的参数是int,如果不进行&0xff,那么当一个byte会转换成int时,由于int是32位,而byte只有8位这时会进行补位。。。。。。
* 所以,一个byte跟0xff相与会先将那个byte转化成整形运算,这样,结果中的高的24个比特就总会被清0,于是结果总是我们想要的。

* 3.utf-8编码:中文占用3个字节,英文占用1个字节
* gbk编码:中文占用2个字节,英文占用1个字节
* java采用双字节编码(就是java中的一个字符占两个字节)是utf-16be编码。中文占用2个字节,英文占用2个字节
*
* 4.当你的字节序列是某种编码时,这个时候想把字节序列变成字符串,也需要用这种编码方式,否则会出现乱码

* 5.文本文件 就是字节序列。可以是任意编码的字节序列。
* 如果我们在中文机器上直接创建文本文件,那么该文件只认识ansi编码(例如直接在电脑中创建文本文件)

Java IO流 文件传输基础

二、file类的使用

package com.study.io;
import java.io.file;
/**
* file类的使用
*/
public class filedemo {
/*java.io.file类表示文件或目录
file类只用于表示文件或目录的信息(名称,大小等),不能用于文件内容的访问。*/
public static void main(string[] args) {
file file=new file("d:\\111");//创建文件对象时指定目录需要用双斜杠,因为“\”是转义字符
/*目录的中间的分隔符可以用双斜杠,也可以用反斜杠,也可以用file.separator设置分隔符*/
// file file1=new file("d:"+file.separator);
// system.out.println(file.exists());//exists()判断文件或文件夹是否存在
if(!file.exists()){//如果文件不存在
file.mkdir();//创建文件夹mkdir(),还有mkdirs()创建多级目录
}else{
file.delete();//删除文件或文件夹
}
//判断是否是一个目录isdirectory,如果是目录返回true,如果不是目录或者目录不存在返回false
system.out.println(file.isdirectory());
//判断是否是一个文件isfile
system.out.println(file.isfile());
file file2=new file("d:\\222","123.txt");
//常用api:
system.out.println(file);//打印的是file.tostring()的内容
system.out.println(file.getabsolutepath());//获取绝对路径
system.out.println(file.getname());//获取文件名称
system.out.println(file2.getname());
system.out.println(file.getparent());//获取父级绝对路径
system.out.println(file2.getparentfile().getabsolutepath());
}
}

运行结果:

Java IO流 文件传输基础

说明:

java.io.file类表示文件或目录

file类只用于表示文件或目录的信息(名称,大小等),不能用于文件内容的访问。

常用的api:

1.创建file对象:file file=new file(string path);注意:file.seperater();获取系统分隔符,如:“\”.
2.boolean file.exists();是否存在.
3.file.mkdir();或者file.mkdirs();创建目录或多级目录。
4.file.isdirectory()判断是否是目录
file.isfile()判断是否是文件。
5.file.delete();删除文件或目录。
6.file.createnewfile();创建新文件。
7.file.getname()获取文件名称或目录绝对路径。
8.file.getabsolutepath()获取绝对路径。
9.file.getparent();获取父级绝对路径。

1、遍历目录

package com.study.io;
import java.io.file;
import java.io.ioexception;
/**
* file工具类
* 列出file类的常用操作,比如:过滤、遍历等操作
*/
public class fileutils {
/**
* 列出指定目录下(包括其子目录)的所有文件
* @param dir
* @throws ioexception
*/
public static void listdirectory(file dir) throws ioexception{
if(!dir.exists()){//exists()方法用于判断文件或目录是否存在
throw new illegalargumentexception("目录:"+dir+"不存在");
}
if(!dir.isdirectory()){//isdirectory()方法用于判断file类的对象是否是目录
throw new illegalargumentexception(dir+"不是目录");
}
/*string[] filenames = dir.list();//list()方法用于列出当前目录下的子目录和文件(直接是子目录的名称,不包含子目录下的内容),返回的是字符串数组
for (string string : filenames) {
system.out.println(string);
}*/
//如果要遍历子目录下的内容就需要构造成file对象做递归操作,file提供了直接返回file对象的api
file[] listfiles = dir.listfiles();//返回的是直接子目录(文件)的抽象
if(listfiles !=null && listfiles.length >0){
for (file file : listfiles) {
/*system.out.println(file);*/
if(file.isdirectory()){
//递归
listdirectory(file);
}else{
system.out.println(file);
}
}
}
}
}

测试类:

public class fileutilstest {
public static void main(string[] args) throws ioexception {
fileutils.listdirectory(new file("d:\\iostudy"));
}
}

运行结果:

Java IO流 文件传输基础

三、randomaccessfile类的使用

randomaccessfile:java提供的对文件内容的访问,既可以读文件,也可以写文件。

randomaccessfile支持随机访问文件,可以访问文件的任意位置。

注意 java文件的模型:

Java IO流 文件传输基础

运行结果:

1
12
[65, 66, 127, -1, -1, -1, 127, -1, -1, -1, -42, -48]
7f
ff
ff
ff
7f
ff
ff
ff
d6
d0

四、字节流(fileinputstream、fileoutputstream)

io流可分为输入流和输出流。

这里又可分为字节流和字符流。

Java IO流 文件传输基础

Java IO流 文件传输基础

代码示例:

package com.study.io;
import java.io.bufferedinputstream;
import java.io.bufferedoutputstream;
import java.io.file;
import java.io.fileinputstream;
import java.io.fileoutputstream;
import java.io.ioexception;
/**
* io工具类
* ❤文件输入输出流:
* fileinputstream-->具体实现了在文件上读取数据
* fileoutputstream-->实现了向文件中写出byte数据的方法
* ❤数据输入输出流:
* dataoutputstream / datainputstream:对"流"功能的扩展,可以更加方面的读取int,long,字符等类型数据
* dataoutputstream writeint()/writedouble()/writeutf()
* ❤字节缓冲流:
* bufferedinputstream & bufferedoutputstream
* 这两个流类位io提供了带缓冲区的操作,一般打开文件进行写入或读取操作时,都会加上缓冲,这种流模式提高了io的性能 
* 比如:从应用程序中把输入放入文件,相当于将一缸水倒入到另一个缸中:
fileoutputstream--->write()方法相当于一滴一滴地把水“转移”过去
dataoutputstream-->writexxx()方法会方便一些,相当于一瓢一瓢把水“转移”过去
bufferedoutputstream--->write方法更方便,相当于一瓢一瓢先放入桶中(即缓存区),再从桶中倒入到另一个缸中,性能提高了
*/
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){
/* 0xff换成2进制就是8个1,这样与的话,其实就是取到了字符的低8位。 
* oxf就是15, 小于15的数会转换成一个16进制数,
* 你的代码里希望是固定的两个16进制数,所以当只会产生一个时要加个0*/
if(b <= 0xf){
//单位数前面补0
system.out.print("0");
}
//integer.tohexstring(b)将整型b转换为16进制表示的字符串
system.out.print(integer.tohexstring(b)+" ");
if(i++%10==0){
system.out.println();
}
}
in.close();//文件读写完成以后一定要关闭
}
/**
* 批量读取,对大文件而言效率高,也是我们最常用的读文件的方式
* @param filename
* @throws ioexception
*/
public static void printhexbybytearray(string filename)throws ioexception{
fileinputstream in = new fileinputstream(filename);
byte[] buf = new byte[8 * 1024];
/*从in中批量读取字节,放入到buf这个字节数组中,
* 从第0个位置开始放,最多放buf.length个 
* 返回的是读到的字节的个数
*/
/*int bytes = in.read(buf,0,buf.length);//一次性读完,说明字节数组足够大
int j = 1; 
for(int i = 0; i < bytes;i++){
system.out.print(integer.tohexstring(buf[i] & 0xff)+" ");
if(j++%10==0){
system.out.println();
}
}*/
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)+" ");
/**
* & 0xff:byte类型8位,int类型32位,为了避免数据转换错误,通过&0xff将高24位清零
*/
if(j++%10==0){
system.out.println();
}
}
}
in.close();
}
/**
* 文件拷贝,字节批量读取
* @param srcfile
* @param destfile
* @throws ioexception
*/
public static void copyfile(file srcfile, file destfile) throws ioexception {
if (!srcfile.exists()) {
throw new illegalargumentexception("文件:" + srcfile + "不存在");
}
if (!srcfile.isfile()) {
throw new illegalargumentexception(srcfile + "不是文件");
}
fileinputstream in = new fileinputstream(srcfile);
fileoutputstream out = new fileoutputstream(destfile);//文件不存在时,会直接创建;如果存在,删除后建
byte[] buf = new byte[8 * 1024];//批量读写
int b;
while ((b = in.read(buf, 0, buf.length)) != -1) {//read(buf,0,buf.length)带参数的read返回的是字节的总长度;当全部读完后返回的是-1;
out.write(buf, 0, b);
out.flush();// 最好加上
}
in.close();
out.close();
}
/**
* 进行文件的拷贝,利用带缓冲的字节流
* @param srcfile
* @param destfile
* @throws ioexception
*/
public static void copyfilebybuffer(file srcfile,file destfile)throws ioexception{
if(!srcfile.exists()){
throw new illegalargumentexception("文件:"+srcfile+"不存在");
}
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();
}
/**
* 单字节,不带缓冲进行文件拷贝
* @param srcfile
* @param destfile
* @throws ioexception
*/
public static void copyfilebybyte(file srcfile,file destfile)throws ioexception{
if(!srcfile.exists()){
throw new illegalargumentexception("文件:"+srcfile+"不存在");
}
if(!srcfile.isfile()){
throw new illegalargumentexception(srcfile+"不是文件");
}
fileinputstream in = new fileinputstream(srcfile);
fileoutputstream out = new fileoutputstream(destfile);
int c ;
while((c = in.read())!=-1){//read()不带参数的read返回的是读到的字节内容;当全部读完后返回的都是是-1;
out.write(c);
out.flush();
}
in.close();
out.close();
}
}

测试类:

package com.study.io;
import java.io.file;
import java.io.ioexception;
import org.junit.test;
public class ioutiltest {
@test
public void testprinthex() {
try {
ioutil.printhex("d:\\javaio\\fileutils.java");
} catch (ioexception e) {
e.printstacktrace();
}
}
@test
public void testprinthexbybytearray() {
try {
long start = system.currenttimemillis();//当前时间与协调世界时 1970 年 1 月 1 日午夜之间的时间差(以毫秒为单位测量)
//ioutil.printhexbybytearray("e:\\javaio\\fileutils.java");
//ioutil.printhex("e:\\javaio\\1.mp3");
ioutil.printhexbybytearray("e:\\javaio\\1.mp3");
system.out.println();
long end = system.currenttimemillis();
system.out.println(end - start);
} catch (ioexception e) {
e.printstacktrace();
}
}
@test
public void testcopyfile(){
try {
ioutil.copyfile(new file("d:\\javaio\\1.txt"), new file("d:\\javaio\\1copy.txt"));
} catch (ioexception e) {
e.printstacktrace();
}
}
@test
public void testcopyfilebybuffer(){
try {
long start = system.currenttimemillis();
/*ioutil.copyfilebybyte(new file("e:\\javaio\\1.mp3"), new file(
"e:\\javaio\\2.mp3"));*/ //两万多毫秒
/*ioutil.copyfilebybuffer(new file("e:\\javaio\\1.mp3"), new file(
"e:\\javaio\\3.mp3"));//一万多毫秒*/
ioutil.copyfile(new file("e:\\javaio\\1.mp3"), new file(
"e:\\javaio\\4.mp3"));//7毫秒
long end = system.currenttimemillis();
system.out.println(end - start );
} catch (ioexception e) {
e.printstacktrace();
} 
}
}

五、字符流

Java IO流 文件传输基础

package com.study.io;
import java.io.fileinputstream;
import java.io.fileoutputstream;
import java.io.ioexception;
import java.io.inputstreamreader;
import java.io.outputstreamwriter;
public class israndoswdemo {
public static void main(string[] args)throws ioexception {
fileinputstream in = new fileinputstream("e:\\javaio\\utf8.txt");
inputstreamreader isr = new inputstreamreader(in,"utf-8");//默认项目的编码,操作的时候,要写文件本身的编码格式
fileoutputstream out = new fileoutputstream("e:\\javaio\\utf81.txt");
outputstreamwriter osw = new outputstreamwriter(out,"utf-8");
/*int c ;
while((c = isr.read())!=-1){
system.out.print((char)c);
}*/
char[] buffer = new char[8*1024];
int c;
/*批量读取,放入buffer这个字符数组,从第0个位置开始放置,最多放buffer.length个返回的是读到的字符的个数*/
while(( c = isr.read(buffer,0,buffer.length))!=-1){
string s = new string(buffer,0,c);
system.out.print(s);
osw.write(buffer,0,c);
osw.flush();
}
isr.close();
osw.close();
}
}

字符流之文件读写流(filereader/filewriter)

Java IO流 文件传输基础

字符流的过滤器

Java IO流 文件传输基础

六、对象的序列化和反序列化

Java IO流 文件传输基础

示例:

Java IO流 文件传输基础

Java IO流 文件传输基础

注意:

Java IO流 文件传输基础