RandomAccessFile随机流
随机访问,可以读和写,由构造器的第二个String类型的参数
mode决定,通过seek文件指针偏移函数就可完成文件随机读写
继承关系
Constructor Summary
Constructor | Description |
---|---|
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 Type | Description |
---|---|
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
Constructor | Description |
---|---|
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 Type | Description |
---|---|
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");
}
}