您的位置:首页 > 编程语言 > Java开发

java-IO流(下)

2015-06-07 08:38 465 查看

java-IO流(下)

一、文件的切割和合并

(1)使用IO流进行文件的切割

在现实中我们经常遇到这样的需求就是在某些网站上传附件的时候,附件的大小不可以超过1M或者是其他设置的大小,我们上传的附件往往都大于1M所以这就需要我们用到IO流的切割。

在文件切割之后需要肯定还有文件的合并的操作,那么要合并文件的时候怎么知道这个文件有多少碎片文件呢还有就是需要合并成什么样后缀名格式的文件呢,所有这些需要我们在文件切割的时候就进行生成配置文件信息,在合并文件的时候再对配置文件进行读取。

<span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">public class HeiMaTest {
public static void main(String[] args) throws Exception{
//构建要切割的文件对象
File file = new File("F:\\山建大毕业论文管理系统.apk");
FileInputStream fis = new FileInputStream(file);
//构建切割文件时的配置文件对象
Properties properties = new Properties();
//自定以缓存区大小为1M
byte[] buffer = new byte[1024*1024];
int count = 1;
int len = 0;
//创建写入的目录
File dir = new File("F:\\HeiMaTest");
dir.mkdir();
FileOutputStream fos = null;
while((len = fis.read(buffer))!=-1){
fos = new FileOutputStream(new File(dir,(count++)+".part"));
fos.write(buffer, 0, len);
fos.close();
}
//为集合中填充数据
properties.setProperty("count", String.valueOf(count));
properties.setProperty("filename", file.getName());
//构建输入流将集合中的信息写入文件
FileWriter properties_fos = new FileWriter(new File(dir,(count)+".properties"));
properties.store(properties_fos, "");
fis.close();
properties_fos.close();
}
}</span></span></span>
切之前的文件大小



切之后的截图



通过比较可以发现切割文件后没有丢失信息。

(2)使用IO流进行文件的合并

上面我们将文件切割后下面我们进行文件的合并,在合并的时候我们先读取配置文件的信息根据配置文件确定我们需要合成多少碎片文件,要合成的文件名是什么。

<span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">public class HeiMaTest {
public static void main(String[] args) throws Exception{
//首先获取输入流这里需要使用到的就是序列化流了因为有多个输入流
File dir = new File("F:\\HeiMaTest");
//将输入流都存入一个集合
ArrayList<FileInputStream> lists = new ArrayList<FileInputStream>();
//首先遍历目标文件夹下面的文件过滤配置文件
File[] files = dir.listFiles(new MySuffixFileFilter(".properties"));
if (files.length!= 1) {
System.out.println("配置文件异常");
return;
}
File config = files[0];
//构建Properties的对象
Properties properties = new Properties();
properties.load(new FileReader(config));
//从配置文件中读取要合成文件的名称
String filename = properties.getProperty("filename");
int    count    = Integer.valueOf(properties.getProperty("count"));
for(int i = 1;i<count;i++){
lists.add(new FileInputStream(new File(dir, i+".part")));
}
//使用集合的工具类将ArrayList集合往枚举方向进行转换
Enumeration<FileInputStream> enums= Collections.enumeration(lists);
SequenceInputStream sis = new SequenceInputStream(enums);
//创建生成的目的文件
FileOutputStream fos = new FileOutputStream(new File(dir,filename));
//对序列化流进行读取并且写入到目标文件完成文件的合并
byte[] buffer = new byte[1024];
int len = 0;
while((len = sis.read(buffer))!= -1){
fos.write(buffer, 0, len);
}
sis.close();
fos.close();
}

private static class MySuffixFileFilter implements FileFilter{

private String suffix;
public MySuffixFileFilter(String suffix) {
this.suffix = suffix;
}

@Override
public boolean accept(File pathname) {
// TODO Auto-generated method stub
return pathname.getName().endsWith(suffix);
}
}
}</span></span></span>
运行效果截图



二、操作对象的流

我们如何将java对象直接持久化到硬盘呢?这就需要我们使用对象流了。ObjectOutputStream将Java对象的基本数据类型和图形写入OutputStream,通过在流中使用文件可以实现对象额持久化存储。需要注意的就是被操作的对象需要实现Serializable接口。
(1)将java类School的对象存入本地文件中
<span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">public class HeiMaTest {
public static void main(String[] args) throws Exception{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("F:\\obj.obj"));
oos.writeObject(new School("山东建筑大学", "省属", 69));
oos.close();
}
}</span></span></span>
(2)将存入的对象反序列化出来
<span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">public class HeiMaTest {
public static void main(String[] args) throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("F:\\obj.obj"));
School school = (School)ois.readObject();
System.out.println("学校名称:"+school.getName()+" 学校类型:"+school.getType()+"学校历史:"+school.getHistory());
ois.close();
}
}</span></span></span>
运行效果截图



特别注意的是在存入对象的时候被transient修饰的字段和静态的字段不会持久化到硬盘上

三、IO包里面的其他类

(1)RandomAccessFile
此类的实例支持对随机访问文件的读取和写入,随机访问文件的行为类似存储在文件系统中的一个大型的byte数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。可以通过getFilePoint的方法获取文件的指针,seek方法设置文件的指针。
其实该类的对象就是对字节的输入流和输出流做了封装,该对象的源或者是目的只能是文件,通过构造函数可以看出。在其构造方法中有模式的参数,这个参数到时候传值的时候只可以传4个分别是"r"表示以只读的方式打开,“rw”打开以便读取和写入,如果该文件尚不存在则尝试创建该文件。"rws"在读取和写入的基础上,在发生更新操作的时候,更新的文件内容和元数据都同步写入底层存储设备。"rwd"在读取和写入的基础上,要求将更新文件内容写入底层存储设备中。

1.1 使用RandomAccessFile进行写入

在调用写入方法的时候write(byte[] b),write(int i)前者是写入byte数组,后者是写入一个字节而writeInt(int i)是按照4个字节将int写入

<span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">public class HeiMaTest {

public static void main(String[] args) throws Exception {
RandomAccessFile raf = new RandomAccessFile("D:\\HeiMa.txt", "rw");
raf.write("黑马".getBytes("GBK"));
raf.writeInt(90);
raf.close();
}
}</span></span></span>

1.2 使用RandomAccessFile进行读取

在读取的时候上面的中文要使用中文缓存区来读取,对于存入的int的则直接调用读取int的方法。
<span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">public class HeiMaTest {

public static void main(String[] args) throws Exception {
RandomAccessFile raf = new RandomAccessFile("D:\\HeiMa.txt", "rw");
byte[] buffer  = new byte[4];
raf.read(buffer);
System.out.println(new String(buffer,"GBK"));
System.out.println(raf.readInt());
}
}</span></span></span>
运行效果图



1.3 使用RandomAccessFile进行随机读取和写入

如果我们现在想直接读取那个整数呢,只能设置指针位置了我们直接跳过黑马汉字的四个字节。

<span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">public class HeiMaTest {

public static void main(String[] args) throws Exception {
RandomAccessFile raf = new RandomAccessFile("D:\\HeiMa.txt", "rw");
raf.seek(4);
System.out.println(raf.readInt());
}
}</span></span></span>
如果我们想在在90的后面继续写入数据呢,那么就将指针跳过8,再调用写入的方法。

<span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">public class HeiMaTest {

public static void main(String[] args) throws Exception {
RandomAccessFile raf = new RandomAccessFile("D:\\HeiMa.txt", "rw");
raf.seek(8);
raf.write("程序员".getBytes("GBK"));
}
}</span></span></span>




四、管道流

管道输入流应该连接到管道输出流,管道输入流提供写入管道输出流的所有数据字节,通常数据从一个线程中进行读取,使用另一个线程进行写入。

下面我们分别创建两个线程一个线程来进行数据的读取,另外的一个线程进行数据的写入,需要注意的是不要忘了将管道的输入流和管道的输出流联系起来,可以在实例化管道的输入流的时候在构造器中传入要连接的管道的输出流同样也可以使用管道输入流中的connect的方法进行连接。

<span style="font-size:14px;"><span style="font-size:14px;">public class HeiMaTest {

public static void main(String[] args) throws Exception {
PipedInputStream input = new PipedInputStream();
PipedOutputStream output = new PipedOutputStream();
input.connect(output);
new Thread(new Input(input)).start();
new Thread(new Output(output)).start();
}

private static class Input implements Runnable{
private PipedInputStream in;
public Input(PipedInputStream in) {
this.in = in;
}
@Override
public void run() {
try {
byte[] b = new byte[1024];
int len = 0;
if ((len=in.read(b))!=-1) {
System.out.println(new String(b,0,len));
}
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

private static class Output implements Runnable{
private PipedOutputStream out;
public Output(PipedOutputStream out) {
this.out = out;
}
@Override
public void run() {
try {
Thread.sleep(5000);
out.write("我是管道,我写入数据".getBytes());
out.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
}
}</span></span>


五、操作基本数据类型的流对象

DataOutputStream允许应用程序以适当的方式将基本java数据类型写入输出流中,然后应用程序可以使用数据输入流进行读取而DataInputStream允许允许应用程序以与机器无关的方式从底层输入流中读取java基本数据类型。

<span style="font-size:14px;"><span style="font-size:14px;">public class HeiMaTest {

public static void main(String[] args) throws Exception {
DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:\\HeiMa.txt"));
DataInputStream  din = new DataInputStream(new FileInputStream("D:\\HeiMa.txt"));
dos.writeInt(97);
dos.writeChar('我');
dos.writeInt(98);
dos.close();
System.out.println(din.readInt());
System.out.println(din.readChar());
System.out.println(din.readInt());
din.close();
}
}</span></span>
运行效果截图



六、操作数组的流

ByteArrayOutputStream此类实现了一个输出流,其中的数据被写入一个byte数组,缓冲区会随着数据的不断的写入而自动增长,可以使用toByteArray()和toString()来获取数据。

ByteArrayInputStream包含一个内部缓冲区,该缓冲区包含从流中读取的字节,内部计数器跟踪read方法要提供的下一个字节。

需要注意的是在字节的输入流和输出流中调用流的关闭方法是无效的。

<span style="font-size:14px;"><span style="font-size:14px;">public class HeiMaTest {

public static void main(String[] args) throws Exception {
ByteArrayInputStream  bis = new ByteArrayInputStream("黑马程序员".getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int len = 0;
while((len = bis.read())!=-1){
bos.write(len);
}
System.out.println(bos.toString());
}
}</span></span>
运行效果

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: