127.RandomAccessFile随机流、SequenceInputStream合并流(序列流)

RandomAccessFile随机流

随机访问,可以读和写,由构造器的第二个String类型的参数
mode决定,通过seek文件指针偏移函数就可完成文件随机读写

继承关系
Constructor Summary
ConstructorDescription
RandomAccessFile (File file, String mode)Creates a random access file stream to read from, and optionally to write to, the file specified by the File argument.
RandomAccessFile (String name, String mode)Creates a random access file stream to read from, and optionally to write to, a file with the specified name.
Method Summary
Method Modifier and TypeDescription
void close()Closes this random access file stream and releases any system resources associated with the stream.
FileChannel getChannel()Returns the unique FileChannel object associated with this file.
FileDescriptor getFD()Returns the opaque file descriptor object associated with this stream.
long getFilePointer()Returns the current offset in this file.
long length()Returns the length of this file.
int read()Reads a byte of data from this file.
int read(byte[] b)Reads up to b.length bytes of data from this file into an array of bytes.
int read(byte[] b, int off, int len)Reads up to len bytes of data from this file into an array of bytes.
boolean readBoolean()Reads a boolean from this file.
byte readByte()Reads a signed eight-bit value from this file.
char readChar()Reads a character from this file.
double readDouble()Reads a double from this file.
float readFloat()Reads a float from this file.
void readFully(byte[] b)Reads b.length bytes from this file into the byte array, starting at the current file pointer.
void readFully(byte[] b, int off, int len)Reads exactly len bytes from this file into the byte array, starting at the current file pointer.
int readInt()Reads a signed 32-bit integer from this file.
String readLine()Reads the next line of text from this file.
long readLong()Reads a signed 64-bit integer from this file.
short readShort()Reads a signed 16-bit number from this file.
int readUnsignedByte()Reads an unsigned eight-bit number from this file.
int readUnsignedShort()Reads an unsigned 16-bit number from this file.
String readUTF()Reads in a string from this file.
void seek(long pos)Sets the file-pointer offset, measured from the beginning of this file, at which the next read or write occurs.
void setLength(long newLength)Sets the length of this file.
int skipBytes(int n)Attempts to skip over n bytes of input discarding the skipped bytes.
void write(byte[] b)Writes b.length bytes from the specified byte array to this file, starting at the current file pointer.
void write(byte[] b, int off, int len)Writes len bytes from the specified byte array starting at offset off to this file.
void write(int b)Writes the specified byte to this file.
void writeBoolean(boolean v)Writes a boolean to the file as a one-byte value.
void writeByte(int v)Writes a byte to the file as a one-byte value.
void writeBytes(String s)Writes the string to the file as a sequence of bytes.
void writeChar(int v)Writes a char to the file as a two-byte value, high byte first.
void writeChars(String s)Writes a string to the file as a sequence of characters.
void writeDouble(double v)Converts the double argument to a long using the doubleToLongBits method in class Double, and then writes that long value to the file as an eight-byte quantity, high byte first.
void writeFloat(float v)Converts the float argument to an int using the floatToIntBits method in class Float, and then writes that int value to the file as a four-byte quantity, high byte first.
void writeInt(int v)Writes an int to the file as four bytes, high byte first.
void writeLong(long v)Writes a long to the file as eight bytes, high byte first.
void writeShort(int v)Writes a short to the file as two bytes, high byte first.
void writeUTF(String str)Writes a string to the file using modified UTF-8 encoding in a machine-independent manner.
RandomAccessFile测试
package cn.yzy.io;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class testRandomAccessFile {
	public static void main(String[] args) throws IOException{
//		test1();
//		test2();
		test3();
	}
	
	//指定起始位置,一直读取到文件尾
	public static void test1() throws IOException {
		RandomAccessFile raf = new RandomAccessFile(new File("printWriter.txt"), "r");
		//随机
		raf.seek(6);
		
		//读取
		byte[] flush = new byte[1024];
		int len = -1;
		while((len = raf.read(flush)) != -1) {
			System.out.println(new String(flush, 0, len));
		}
		raf.close();
	}
	
	
	
	//分块读取/起始、实际大小 
	public static void test2() throws IOException {
		RandomAccessFile raf = new RandomAccessFile(new File("src/cn/yzy/io/objectStreamTest02.java"), "r");
		//起始位置
		int beginPos = 2;
		
		//实际大小
		int actualSize = 1026;
		
		//随机
		raf.seek(beginPos);
		
		//读取
		byte[] flush = new byte[1024];
		int len = -1;
		while((len = raf.read(flush)) != -1) {
			if(actualSize > len) {
				System.out.println(new String(flush, 0, len));
				actualSize -= len;
			}else {
				System.out.println(new String(flush, 0, actualSize));
				break;
			}
		}
		raf.close();
	}
	
	
	
	
	
	//分块大小的问题
	public static void test3() throws IOException {
		File srcFile = new File("src/cn/yzy/io/objectStreamTest02.java");
//		RandomAccessFile raf = new RandomAccessFile(new File("src/cn/yzy/io/objectStreamTest02.java"), "r");
		
		//总长度
		long len = srcFile.length();
		//块大小
		long blockSize = 1024;
		//块个数(向上取整)
		long size = (long)Math.ceil(len*1.0/blockSize); 
//		System.out.println(len);
		
		//块索引
		long beginPos = 0;
		long actualSize = blockSize - 1;
		
		int hasDown = 0;
		while(hasDown < size) {
			System.out.println("block " + hasDown + ": [begin: "+beginPos+", end:"+actualSize+"]");
			//操作[beginPos, endPos]
			split(beginPos, actualSize, srcFile);
			beginPos += blockSize;
			if(hasDown == size-1)
				actualSize = len-1;
			hasDown++;
		}
	}
	
	public static void split(long beginPos, long actualSize, File srcFile) throws IOException {
		RandomAccessFile raf = new RandomAccessFile(srcFile, "r");
		//随机
		raf.seek(beginPos);
		
		//读取
		byte[] flush = new byte[1024];
		int len = -1;
		while((len = raf.read(flush)) != -1) {
			if(actualSize > len) {
				System.out.println(new String(flush, 0, len));
				actualSize -= len;
			}else {
				System.out.println(new String(flush, 0, (int)actualSize));
				break;
			}
		}
		raf.close();
	}
}

test1实现了文件指针起始位置的设定

test2解决了设置起始不能读取指定长度的问题,通过设置实际长度即可从起始读取指定字长从而达到分块的目的

test3实现了分块分多少块的问题,最后一块可能不够块字长大小,需要向上取整,紧接着split函数对test2进行了封装,实现了读取每一块的功能

RandomAccessFile文本按块输出到文件
package cn.yzy.io;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class testRandomAccessFile02 {
	public static void main(String[] args) throws IOException{
		test3();
	}
	
	
	//分块大小的问题
	public static void test3() throws IOException {
		File srcFile = new File("src/cn/yzy/io/objectStreamTest02.java");
//		RandomAccessFile raf = new RandomAccessFile(new File("src/cn/yzy/io/objectStreamTest02.java"), "r");
		
		//总长度
		long len = srcFile.length();
		//块大小
		long blockSize = 1024;
		//块个数(向上取整)
		long size = (long)Math.ceil(len*1.0/blockSize); 
//		System.out.println(len);
		
		//块索引
		long beginPos = 0;
		long actualSize = blockSize - 1;
		
		int hasDown = 0;
		while(hasDown < size) {
			System.out.println("block " + hasDown + ": [begin: "+beginPos+", end:"+actualSize+"]");
			//操作[beginPos, endPos]
			split(beginPos, actualSize, hasDown);
			beginPos += blockSize;
			if(hasDown == size-1)
				actualSize = len-1;
			hasDown++;
		}
	}
	
	public static void split(long beginPos, long actualSize, int hasDown) throws IOException {
		RandomAccessFile raf = new RandomAccessFile(new File("randomAccessBlockWrite/"+"block"+ hasDown +"Copy.java"), "rw");
		//随机
		raf.seek(beginPos);
		
		//读取
		byte[] flush = new byte[1024];
		int len = -1;
		while((len = raf.read(flush)) != -1) {
			if(actualSize > len) {
//				System.out.println(new String(flush, 0, len));
				raf.write(flush, 0, len);
				actualSize -= len;
			}else {
//				System.out.println(new String(flush, 0, (int)actualSize));
				raf.write(flush, 0, (int)actualSize);
				break;
			}
		}
		raf.close();
	}
}

分块文本如下,文本可以正常查看

RandomAccessFile图片按块输出到文件
package cn.yzy.io;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class testRandomAccessFile03 {
	public static void main(String[] args) throws IOException{
		test3();
	}
	
	
	public static void test3() throws IOException {
		File srcFile = new File("夜晚较为活泼之物种对照图.jpg");
//		RandomAccessFile raf = new RandomAccessFile(new File("src/cn/yzy/io/objectStreamTest02.java"), "r");
		
		//总长度
		long len = srcFile.length();
		//块大小
		long blockSize = 10240;
		//块个数(向上取整)
		long size = (long)Math.ceil(len*1.0/blockSize); 
//		System.out.println(len);
		
		//块索引
		long beginPos = 0;
		long actualSize = blockSize - 1;
		
		int hasDown = 0;
		while(hasDown < size) {
			System.out.println("block " + hasDown + ": [begin: "+beginPos+", end:"+actualSize+"]");
			//操作[beginPos, endPos]
			split(beginPos, actualSize, hasDown);
			beginPos += blockSize;
			if(hasDown == size-1)
				actualSize = len-1;
			hasDown++;
		}
	}
	
	public static void split(long beginPos, long actualSize, int hasDown) throws IOException {
		RandomAccessFile raf = new RandomAccessFile(new File("randomAccessBlockWriteJpg/"+"block"+ hasDown +"Copy.jpg"), "rw");
		//随机
		raf.seek(beginPos);
		
		//读取
		byte[] flush = new byte[1024];
		int len = -1;
		while((len = raf.read(flush)) != -1) {
			if(actualSize > len) {
				raf.write(flush, 0, len);
				actualSize -= len;
			}else {
				raf.write(flush, 0, (int)actualSize);
				break;
			}
		}
		raf.close();
	}
}

如下:分块的图片是不能打开的

对分块功能进行封装
package cn.yzy.io;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;


public class splitFile {
	//数据来源
	private File src;
	//存储分块的路径
	private String destDir;
	//存储路径列表
	private List<String> destPaths;
	//块大小
	private int blockSize;
	//块数
	private int size;
	
	
	
	public splitFile(File src, String destDir, int blockSize) {
		super();
		this.src = src;
		this.destDir = destDir;
		this.blockSize = blockSize;
		this.destPaths = new ArrayList<String>();
		init();
	}

	private void init() {
		//长度
		long len = this.src.length();
		//块数
		this.size = (int) Math.ceil(len*1.0/blockSize);
		//路径
		for(int i=0; i<size; ++i) {
			this.destPaths.add(this.destDir+"/"+ i +"-"+this.src.getName());
		}
	}

	public void split() throws IOException {
		//长度
		long len = this.src.length();
		//起始
		int beginPos = 0;
		//第几块
		int i = 0;
		int actualSize = this.blockSize;
		while(i < size) {
			splitDetail(i, beginPos, actualSize);
			++i;
			if(i == size - 1)
				actualSize = (int) (len % blockSize);
			beginPos += this.blockSize;
		}
	}
	
	private void splitDetail(int i, int beginPos, int actualSize) throws IOException {
		RandomAccessFile rafR = new RandomAccessFile(this.src, "r");
		RandomAccessFile rafW = new RandomAccessFile(this.destPaths.get(i), "rw");
		//随机
		rafR.seek(beginPos);
		
		//读取
		byte[] flush = new byte[this.blockSize];
		//块数
		int block = 0;
		while(block < this.size) {
			rafR.read(flush, 0, actualSize);
			rafW.write(flush, 0, actualSize);
			++block;
		}
		rafR.close();
		rafW.close();
	}

	public static void main(String[] args) throws IOException {
		splitFile sf = new splitFile(new File("src/cn/yzy/io/objectStreamTest02.java"), "randomAccessBlockWriteCapsulation", 1024);
		sf.split();
	}
}

只需要给封装的类的实例构造时传递初始化参数File数据源、String分块要保存的路径、int块大小。调用split成员函数就可完成分块存储到指定路径

对以上封装的分割类增加合并方法
package cn.yzy.io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;


public class splitFile {
	//数据来源
	private File src;
	//存储分块的路径
	private String destDir;
	//存储路径列表
	private List<String> destPaths;
	//块大小
	private int blockSize;
	//块数
	private int size;
	
	
	
	public splitFile(File src, String destDir, int blockSize) {
		super();
		this.src = src;
		this.destDir = destDir;
		this.blockSize = blockSize;
		this.destPaths = new ArrayList<String>();
		init();
	}

	private void init() {
		//长度
		long len = this.src.length();
		//块数
		this.size = (int) Math.ceil(len*1.0/blockSize);
		//路径
		for(int i=0; i<size; ++i) {
			this.destPaths.add(this.destDir+"/"+ i +"-"+this.src.getName());
		}
	}

	//文件分割
	public void split() throws IOException {
		//长度
		long len = this.src.length();
		//起始
		int beginPos = 0;
		//第几块
		int i = 0;
		int actualSize = this.blockSize;
		while(i < size) {
			splitDetail(i, beginPos, actualSize);
			++i;
			if(i == size - 1)
				actualSize = (int) (len % blockSize);
			beginPos += this.blockSize;
		}
	}
	
	private void splitDetail(int i, int beginPos, int actualSize) throws IOException {
		RandomAccessFile rafR = new RandomAccessFile(this.src, "r");
		RandomAccessFile rafW = new RandomAccessFile(this.destPaths.get(i), "rw");
		//随机
		rafR.seek(beginPos);
		
		//读取
		byte[] flush = new byte[this.blockSize];
		//块数
		int block = 0;
		while(block < this.size) {
			rafR.read(flush, 0, actualSize);
			rafW.write(flush, 0, actualSize);
			++block;
		}
		rafR.close();
		rafW.close();
	}
	
	//文件合并
	public void merge(String destPath) throws IOException {
		//输出流
		OutputStream os = new BufferedOutputStream(new FileOutputStream(destPath, true));
		//FileOutputStream第二个参数给定true追加写
		for(int i=0; i<destPaths.size(); ++i) {
			InputStream is = new BufferedInputStream(new FileInputStream(destPaths.get(i)));
			//拷贝
			byte[] flush = new byte[this.blockSize];
			int len = -1;
			while((len = is.read(flush)) != -1) {
				os.write(flush, 0, len);
			}
			os.flush();
			is.close();
		}
		os.close();
	}
	

	public static void main(String[] args) throws IOException {
		splitFile sf = new splitFile(new File("src/cn/yzy/io/objectStreamTest02.java"), "randomAccessBlockWriteCapsulation", 1024);
		sf.split();
		sf.merge("merge.java");
	}
}

发现调用merge方法可以正常合并,但是实用并不是很方便,因此引入以下SequenceInputStream合并流的学习

SequenceInputStream合并流

继承关系
Constructor Summary
ConstructorDescription
SequenceInputStream(InputStream s1, InputStream s2)Initializes a newly created SequenceInputStream by remembering the two arguments, which will be read in order, first s1 and then s2, to provide the bytes to be read from this
SequenceInputStream(Enumeration<? extends InputStream> e)Initializes a newly created SequenceInputStream by remembering the argument, which must be an Enumeration that produces objects whose run-time type is InputStream.
Method Summary
Method Modifier and TypeDescription
int available()Returns an estimate of the number of bytes that can be read (or skipped over) from the current underlying input stream without blocking by the next invocation of a method for
void close()Closes this input stream and releases any system resources associated with the stream.
int read()Reads the next byte of data from this input stream.
int read(byte[] b, int off, int len)Reads up to len bytes of data from this input stream into an array of bytes.
对上述分割合并的类的merge方法使用SequenceInputStream进行改进
//文件合并
	public void mergeSequence(String destPath) throws IOException {
		//输出流
		OutputStream os = new BufferedOutputStream(new FileOutputStream(destPath, true));
		Vector<InputStream> vi = new Vector<InputStream>();
		SequenceInputStream sis = null;
		
		
		//将分块的文件路径放入Vector容器里(List也可)
		for(int i=0; i<destPaths.size(); ++i) {
			vi.add(new BufferedInputStream(new FileInputStream(destPaths.get(i))) );
		}
		
		//放入序列容器中
		sis = new SequenceInputStream(vi.elements());
		//拷贝
		byte[] flush = new byte[this.blockSize];
		int len = -1;
		while((len = sis.read(flush)) != -1) {
			os.write(flush, 0, len);
		}
		os.flush();
		sis.close();
		os.close();
	}

发现依然可以正常合并文件,包括图片文件如下:

SequenceInputStream合并流合并文本和图片的测试完整代码如下
package cn.yzy.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;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;


public class splitFile {
	//数据来源
	private File src;
	//存储分块的路径
	private String destDir;
	//存储路径列表
	private List<String> destPaths;
	//块大小
	private int blockSize;
	//块数
	private int size;
	
	
	
	public splitFile(File src, String destDir, int blockSize) {
		super();
		this.src = src;
		this.destDir = destDir;
		this.blockSize = blockSize;
		this.destPaths = new ArrayList<String>();
		init();
	}

	private void init() {
		//长度
		long len = this.src.length();
		//块数
		this.size = (int) Math.ceil(len*1.0/blockSize);
		//路径
		for(int i=0; i<size; ++i) {
			this.destPaths.add(this.destDir+"/"+ i +"-"+this.src.getName());
		}
	}

	//文件分割
	public void split() throws IOException {
		//长度
		long len = this.src.length();
		//起始
		int beginPos = 0;
		//第几块
		int i = 0;
		int actualSize = this.blockSize;
		while(i < size) {
			splitDetail(i, beginPos, actualSize);
			++i;
			if(i == size - 1)
				actualSize = (int) (len % blockSize);
			beginPos += this.blockSize;
		}
	}
	
	private void splitDetail(int i, int beginPos, int actualSize) throws IOException {
		RandomAccessFile rafR = new RandomAccessFile(this.src, "r");
		RandomAccessFile rafW = new RandomAccessFile(this.destPaths.get(i), "rw");
		//随机
		rafR.seek(beginPos);
		
		//读取
		byte[] flush = new byte[this.blockSize];
		//块数
		int block = 0;
		while(block < this.size) {
			rafR.read(flush, 0, actualSize);
			rafW.write(flush, 0, actualSize);
			++block;
		}
		rafR.close();
		rafW.close();
	}
	
	//文件合并
	public void merge(String destPath) throws IOException {
		//输出流
		OutputStream os = new BufferedOutputStream(new FileOutputStream(destPath, true));
		//FileOutputStream第二个参数给定true追加写
		for(int i=0; i<destPaths.size(); ++i) {
			InputStream is = new BufferedInputStream(new FileInputStream(destPaths.get(i)));
			//拷贝
			byte[] flush = new byte[this.blockSize];
			int len = -1;
			while((len = is.read(flush)) != -1) {
				os.write(flush, 0, len);
			}
			os.flush();
			is.close();
		}
		os.close();
	}
	
	//文件合并
	public void mergeSequence(String destPath) throws IOException {
		//输出流
		OutputStream os = new BufferedOutputStream(new FileOutputStream(destPath, true));
		Vector<InputStream> vi = new Vector<InputStream>();
		SequenceInputStream sis = null;
		
		
		//将分块的文件路径放入Vector容器里(List也可)
		for(int i=0; i<destPaths.size(); ++i) {
			vi.add(new BufferedInputStream(new FileInputStream(destPaths.get(i))) );
		}
		
		//放入序列容器中
		sis = new SequenceInputStream(vi.elements());
		//拷贝
		byte[] flush = new byte[this.blockSize];
		int len = -1;
		while((len = sis.read(flush)) != -1) {
			os.write(flush, 0, len);
		}
		os.flush();
		sis.close();
		os.close();
	}

	public static void main(String[] args) throws IOException {
		splitFile sf = new splitFile(new File("src/cn/yzy/io/objectStreamTest02.java"), "randomAccessBlockWriteCapsulation", 1024);
		sf.split();
		sf.merge("merge.java");
		sf.mergeSequence("mergeSequence.java");
		
		splitFile sfJpg = new splitFile(new File("夜晚较为活泼之物种对照图.jpg"), "randomAccessBlockWriteCapsulationJpg", 10240);
		sfJpg.split();
		sfJpg.merge("mergeJpg.jpg");
		sfJpg.mergeSequence("mergeSequenceJpg.jpg");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值