------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
File类
java中的流只是负责数据的搬运,不能对所操作的数据源或者目的做近一步的分析或是操作如:获取文件名,文件大小,文件是否存在的判断,是否是文件夹,删除等操作;
为此java将文件和文件夹对象向上提取封装成了File;
1 构造函数:
File(String pathname);//将一个已存在或是不存在的文件或是文件夹封装成firel对象
File(File parent, String pathname);
2 常见方法
1 获取
1 获取文件名 getnName();
2 获取文件大小 length();
3 获取文件修改时间 lastModifief();
4 获取文件路径 getPath();
5 获取系统文件分隔符 File.separator();
2 创建合删除
boolean creatNewFile();//当文件存在时不创建,当文件不存在时创建;
boolean delete();//
boolean deleteOnExits();// 当虚拟机退出时删除
文件夹的创建和删除
boolean mkdir();
booean mkdirs();//当File的路径包含父目录是只能用mkdirs();如File f = new File("s\\s1");
boolean delete();//文件夹中存在文件,或是文件正在被流对象处理时不能删除;删除多多级文件目录只删除最里层的文件夹
3 判断
boolean isFile();//判断是否是文件;
boolean isDirectory();//判断是否是文件夹;
注意判断时得先判断文件或是问价是否存在;
4 重命名
blooean reanmeTo(File dest);//
File f1 = new File ("a.txt");
File f2 = new File("c:\\b.txt");
f1.renameTo(f2);
实际进行的操作是:1剪切 2 重命名
5 系统根目录和容量的获取
File[ ] files = File.listRoots();//获取目录内容
String [] list();// 获取当前目录下的所有文件和文件夹的名称包含隐藏的文件;注意调用list()方法的对象必须是文件夹,否则会发生空指针异常;
如果文件夹中没有内容会返还一个长度喂0的数组
String [ ] list(FilenameFileter filter);//定义文件名过滤器对文件夹中的文件进行过滤操作
File[] files listFiles();//获得一个目录下的所有文件对象。
File[] files listFiles(FileFileter);//也可以指明过滤器
1复制文件
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/*
* 复制文本文件
* 1 使用FileReader读取
* 2 使用FileWriter写入
* 3 线程同步? 如何操作
*/
public class copyFileDemo {
private static final int BUFF_SIZE = 1024;
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
copyFile2();
}
public static void copyFile2()
{
// 拷贝一个文件如何处理呢?
/* 找到目标文件,将文件中的内容读取出来,再写入到一个新建的文件中
* 1 找一个能读取字符文件的对象--->Reader 体系
* 2 为读取对象指明要读取的目标文件
* 3 找个能将字符数据写到文件中的对象---->Writer 体系
* 4 指明要往哪儿写
* 5 读写交替进行
* 6 关闭资源
*
* 7:异常处理
* 标准的IO异常处理流程
*
*/
//找一个能读取字符文件的对象
FileReader fr = null;
FileWriter fw = null;
try
{
fr = new FileReader("demo.txt");//指明要操作的目标文件
fw = new FileWriter("demo_copy2.txt");//指明往哪儿写
char[]buff = new char[BUFF_SIZE];//将大小定义为常量
int length = 0;
//读写操作
while((length=fr.read(buff))!=-1)// 读
{
// fw.write(buff);//写存在安全隐患:将最后一次读取数据写入时
fw.write(buff,0,length);//
}
}catch(IOException e)
{
throw new RuntimeException("读写失败");
}finally
{
if(fr != null)//关闭读入流对象
try {
fr.close();
} catch (IOException e) {
// TODO Auto-generated catch block
throw new RuntimeException("关闭失败");
}
if(fw != null)//关闭写入流对象
try {
fw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
throw new RuntimeException("关闭失败");
}
}
}
public static void copyFile() throws IOException
{
//1 创建读字符取流对象
FileReader fr = new FileReader("demo.txt");
//2 创建 字符输出流对象
FileWriter fw = new FileWriter("demo_copy.txt",true);//末尾接着写入
/*3copy动作
* 1 读取一次,写一次
* 2 先读后写;
* 3 当定义的char[]buff大小不能被数据大小整除时copy文件的出错问题
*
*/
char[]buff = new char[1024];//细节1:
while((fr.read(buff))!=-1)
{
fw.write(buff);
}
//4 释放资源
fr.close();
fw.close();
}
}
2 对文件夹的拷贝
package javalearn13;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Filedemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
File f = new File("dirdemo");
copdirdemo(f,"G:\\eclipse4.4\\项目存储\\");
}
public static void copdirdemo(File f,String destpath) //拷贝文件夹
{
String desDirPath = destpath+f.getName();//创建新文件夹的位置
File dir = new File(desDirPath);
dir.mkdirs();//创建多级目录
File[] flies = f.listFiles();
for(File f1 :flies)
{
if(f1.isDirectory())
{
copdirdemo(f1,dir.getAbsolutePath()+File.separator);
}
else//是文件就拷贝文件
{
FileOutputStream fos = null;
FileInputStream fis = null;
try//拷贝时还需判断是否是文本文件
{
fis = new FileInputStream(f1);
File f2 = new File(dir.getAbsolutePath()+File.separator+f1.getName());
f2.createNewFile();
fos = new FileOutputStream(f2);
byte[] buf = new byte[1024];
int num =0;
while((num = fis.read(buf))!=-1)
{
fos.write(buf, 0, num);
fos.flush();
}
}catch(IOException e)
{
}finally
{
if(fis != null)
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(fos !=null)
{
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
}
--------------------------------------------------------------------------
java 中常用的IO封装类
InputStream ,OutputStream,Reader,Writer提供了最基本的针对数据的操作。但其功能不够强大。java为方便开发人员的IO操作,对基本流对象进行了封装,形成了一些功能
强大的装饰类
1 PrintStream
1 用了打印方法可以对多种数据类型值进行打印,并保持数据表示形式。
2 不抛出IOException
3 可直接将数据打印到文件中去类似FileOutputStream
构造函数接收三种数据类型的值:
1 字符串路劲
2 File 对象
3 字节输出流
它的write()低八位的数据
print();将各种数据转成字符串后打印的
2 PrintWriter
PrintWriter;字符打印流
构造函数
1 字符串路劲
2 File 对象
3 字节输出流
4 字符输出流
3 SequenceInputStream;
将多个输入流对象封装成一个SequnecInputStream流对象,用于文件合并操作。SequenceInputStream中的子流对象按照其添加顺一次对源文件进行读取,流读到文件末尾发回-1时会检测是否存在下一个流若存在就执行下个流的操作。知道所有的流都读取数据完毕时SequenceInputStream 会作为整体返回-1;SequenceInputStream进行close()操作时将关闭所有的子流
文件分割与合并例子
package javalearn13;
import java.io.File;
import java.io.FileInputStream;
/*
* 文件切割合并练习
*
*/
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Properties;
public class fileSplitMergeDemo {
private static final int SIZE = 1024*1024;
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//
// File sourcefile = new File("H:\\歌曲\\一泡尿功夫,青春已作古——朴树.mp3");
File destDir = new File("H:\\歌曲\\filepatrts");
// fileSplit(sourcefile,destDir,SIZE*3);
mergeFile(destDir,destDir);
}
/**
*
* @param sourceFile:被切割文件
* @param destDir: 装碎片文件的文件夹
* @param eachSize: 按多大切
* @throws IOException
*/
public static void fileSplit(File sourceFile,File destDir,int eachSize)
{
//1 流关联目标文件
FileInputStream fis = null;
FileOutputStream fos = null;
FileOutputStream fos2 = null;
if(!destDir.exists())
{
destDir.mkdirs();
}
try
{
fis = new FileInputStream(sourceFile);//文件不存在异常
//2 对文件进行切割
byte[] buf = new byte[SIZE];
long readedCount =0;
int length = 0;
int partcount =1;
while((length=fis.read(buf))!=-1)
{
if(readedCount%eachSize ==0)
{
if(fos!=null)
fos.close();
fos = new FileOutputStream(new File(destDir,partcount+".part"));
partcount++;
}
fos.write(buf, 0, length);//对字节流不必刷新
readedCount += SIZE;
}
/*3 将切割信息写入文件
* 文件切割信息为键值对信息
* 涉及到文件的写出
* 所以使用:Properties集合
* */
Properties p = new Properties();
p.setProperty("filepartcount", partcount+"");
p.setProperty("filename", sourceFile.getName());
fos2 = new FileOutputStream(new File(destDir,"filesplit.properties"));
p.store(fos2, "file split info");
}catch(IOException e)
{
throw new RuntimeException("切割文件失败");
}finally
{
if(fos!=null)
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
throw new RuntimeException("关闭输出流失败");
}
if(fos2!=null)
try {
fos2.close();
} catch (IOException e) {
// TODO Auto-generated catch block
throw new RuntimeException("关闭输出流失败");
}
if(fis!= null)
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
throw new RuntimeException("关闭读取流失败");
}
}
}
public static void mergeFile(File sourceDir,File destDir) throws IOException
{
/*
* 合并文件
* 1 读取配置信息
* 2 对源文件夹中的文件进行筛选
* 3 创建SequenceInputStream
* 4 合并
*/
// 找到配置文件
File[] files = sourceDir.listFiles(new suffixFilter(".properties"));//对文件进行过滤
System.out.println(files.length);
if(files.length!=1)
throw new RuntimeException("配置文件不存在或是不唯一");
FileInputStream fis = new FileInputStream(files[0]);
Properties p = new Properties();
p.load(fis);
int partcount = Integer.parseInt(p.getProperty("filepartcount"));
String filename = p.getProperty("filename");
// 对目录中的文件进行合并操作
File[] fileparts = sourceDir.listFiles(new suffixFilter(".part"));
if(fileparts.length != (partcount-1))
{
throw new RuntimeException("获取碎片文件失败");
}
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
//为每个部分文件关联输入流
for(File f:fileparts)
{
al.add(new FileInputStream(f));
}
//创建SequenceInputStream
SequenceInputStream sis = new SequenceInputStream(Collections.enumeration(al));
//开始合并操作
byte[]buf = new byte[1024];
int len=0;
FileOutputStream fos = new FileOutputStream(new File(destDir,filename));
while((len=sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
sis.close();
fos.close();
}
}
4 ObjectOuptStream 和ObjectInputStream
对象序列化输入输出流
针对java开发最基本的特点对象,java基础流对对象(InputSteram,OutputStream)的基础上进行了进一步的装饰,使得可以将对象Object保存到硬盘文件中,提高对象的生命周期
1 将对象序列化输出
ObjectOutputStream oos= new ObjectOutputStream( new FileOutputStream("obj.object"));
oos.writeObject(new person("张三",21));// 使用序列化输出流输出的对象必须实现serilaziable接口
oos.close();
2 反向序列化
//读取序列化对象
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("obj.object"));
person p = (person)ois.readObject();//进行反序列化是会借助该类对象的字节码文件
ois.close();
关于Serializable接口的原理说明
java对实现了Serializable接口的类和对象在编译时会为其设定一个ID用于标示。当A类对象进行序列化输出到硬盘时,对象会有一个序列化ID,当对这个对象进行反序列化时
虚拟机对检测对象的序列化ID了该对象对应的类文件字节码中的序列化ID进行核对,如果不一致就不能反序列化该对象。
建议在实现Serializable接口的类中显示定义序列化ID这样当修改类文件后仍能将原序列化对象进行反序列化。
transient:关键字
注意:序列化写入时,只是写入非瞬态(transient)和非静态数据(因为静态数据不在堆中)
如果不想讲对象的某些数据写入到序列化文件中可使用transient关键字修饰
如:privte transient String name;
-----------------------------------------------------------------
5 RandomAccessFile类
1 该对象既能读又能写
2 该对象内部维护着一个byte数组,并可通过指针操作数组中的元素
3 可以通过getFilepointer方法获取指针的位置,setFilePointer设置指针的位置
4 其实对象就是将字节输入流和字节输出流进行了封装。
5 该对象的源或者目的时能是文件(不能是:socket,System.in。。。。。)
6 构造参数中可指定对文件的操作:r rw rws rwd
、、、、、、、、、、、、、、、、、、、、、
如果文件不存在-->创建
如果文件存在---->不创建
-----------------------------------------------------------------
6 管道流
PipedInputStream 和 PipedOutputStream
通常在读写流之间存在一定的顺序时使用:比如一个流的读必须在另一个流将数据写入后才能读取到数据时可以使用管道
使用管道流通常在多线程下使用避免死锁
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
/*
* 管道流;
* PipedInputStream 和PipedOutputStream
* 再多线程下使用否则易发生死锁
*/
public class PipedStreamDemo {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
PipedInputStream pis= new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream();
pis.connect(pos);
Thread th1 = new Thread(new Input(pis));
Thread th2 = new Thread(new Output(pos));
th1.start();
th2.start();
}
}
class Input implements Runnable
{
private PipedInputStream in ;
public Input(PipedInputStream in) {
super();
this.in = in;
}
public PipedInputStream getIn() {
return in;
}
public void setIn(PipedInputStream in) {
this.in = in;
}
@Override
public void run() {
// TODO Auto-generated method stub
byte[] buf = new byte[1024];
int len =0;
try {
while((len=in.read(buf))!=-1)
{
System.out.print(new String(buf));
}
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Output implements Runnable
{
private PipedOutputStream out;
public Output(PipedOutputStream out) {
super();
this.out = out;
}
public PipedOutputStream getOut() {
return out;
}
public void setOut(PipedOutputStream out) {
this.out = out;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
out.write("从输出管道发来的数据".getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
------------------------------------
7 操作基本数据类型的流
Data0utputStream
啥时候用?
当对基本数据类型写出时!!!!
DataOutputStream dos = new DataOutputStream(new FileOutputStream("test.txt"));
dos.writInt(12);
dos.writBoolen(fals);
....
dos.writeUTF("张三");:将字符串按照UTF—8修改版写出
只能用DataIbputStream 对象读才能获取元数据值
-------------------------------------------
8 操作字节数组的流
ByteArrayInputStream 和 ByteArrayOutputStream
操作字节数组的流
* ByteArrayInputStream
* ByteArrayOuputStream
* 特点:
* 1 数据的源和目的都在内存
* 2 不必关闭流操作,该操作时无效的
* 3 内部有缓冲区
* 4 writeTo(OutputStream);//
* 以下操作盒ByteArrayInputStream类似
* CharArrayInputStream
* CharArrayOutputStream
*
* StringInputStream
* StringOutputStream
ByteArrayInputStream bais = new ByteArrayInputStream("你好啊,吃饭了吗?".getBytes());//创建时需要指明源:就是一个byte[];
ByteArrayOutputStream baos = new ByteArrayOutputStream();//不用再指明目的地:内部存在缓冲区
byte[] buf = new byte[100];
int len=0;
while((len=bais.read(buf))!=-1)
{
baos.write(buf, 0, len);
}
System.out.print(baos.toString());
注意:ByteArrayOutputStream 内部存在一个谎缓冲区
这2个流在操作完数据后不用关闭流,关闭流时无效的
因为没调用系统底层的数据读写操作。
----------------------------------------------------------------------------------------------
IO操作中的编码问题
1 编码
编码表
ASCLL: 一个字节7位表示
ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示。
GB2312:中国的中文编码表.
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
Unicode: 国际标准码,融合了多种文字
所有文字都用2个字节表示,java语言用的是Unicode
UTF-8:最多用三个字节表示一个字字符。:如果能用一个装就一个 不行就2个再就3
注意:在gb2312 :中文都是负数
GBK中:gbk:中文第一个都是负的,第二个不一定
在UTF-8中:中文都是负数
2 编码中的问题
字符串--->字节数组:编码
字节数组---> 字符串 :解码
你好:GBK :-60 -29 -70 -61
你好:utf-8:-28 -67 -96 -27 -91 -67
1 如果你编错了,解不出来。
2 如果编对了,解错了,有可能还有救。
*/
String str = "你好";
byte[] buf = str.getBytes("gbk");//编码
String str1 = new String(buf,"ISO8859-1");
System.out.println(str1);
//补救措施
byte[] buf2 = str1.getBytes("ISO8859-1");//再次编码
String temp = new String(buf2,"gbk");
System.out.println(temp);
但也可能不挽救的情况如下图所示