IO流之切割合并文件

思路

以每块多大的分量去切割成多少块

比方说 1024 的 文件以 500 切,切成 3 块,就是 500、500、24 的三块。最后一块可能装不满 500,那就得取实际数量了,也就是 24 。

3 块文件的起始点就是:

  • 第一块:0,500
  • 第二块:500,1000
  • 第三块:1000,1024

实现要点

  1. 进行读写,读得时候可以使用 RandomAccessFileseek 方法设置开始读取的地方,然后结束的地方再使用输入的结束点进行判断,从而进行分割。
  2. 文件合并,因为 初始化文件的时候就确定了切块后的每块的文件名,只需要将其全部读取出来然后写,记得这里的 new FileOutputStream( file, true ) 构造方法应该这样写,因为是合并文件,所以这里得 是追加

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
public class SplitFileDemo {

// 文件路径
private String filePath;

// 文件大小
private long fileLength;

// 文件名称
private String fileName;

// 以多大来切割文件
private static long blockSize = 1024 * 1024;

// 文件块数
private int size;

// 切割后的文件的存放路径
private String splitDirPath;

// 切割后的每块的文件名
private List<String> splitFilePathList;

public SplitFileDemo() {
this.splitFilePathList = new ArrayList<String>();
}

public SplitFileDemo(String filePath, String destPath) {
this(filePath, blockSize, destPath);
}

public SplitFileDemo(String filePath, long blockSize, String splitDirPath) {
this();
this.filePath = filePath;
this.blockSize = blockSize;
this.splitDirPath = splitDirPath;
init();
}

/**
* @Description: 初始化必须参数,比如说文件切割后的名字,分成几块,之类的
*/
public void init() {
File src = null;
// 如果 文件地址为空,或者文件不存在则终止程序
if (this.filePath == null || !(src = new File(this.filePath)).exists()) {
return;
}
// 该地址为文件夹也终止
if (src.isDirectory()) {
return;
}

File dest = null;
// 如果目标文件不存在则终止程序
if (this.splitDirPath == null) {
return;
}
dest = new File(this.splitDirPath);
// 如果目标文件不存在则创建
if (!dest.exists()) {
dest.mkdirs();
}

// 文件大小
this.fileLength = src.length();

// 文件名称
this.fileName = src.getName();

if (this.blockSize > this.fileLength) {
this.blockSize = this.fileLength;
}

// 分块
this.size = (int) Math.ceil((src.length() * 1.0 / this.blockSize));

initDestFileName();
}

/**
* @Description: 初始化切割后的文件的名称
*/
public void initDestFileName() {
for (int i = 0; i < this.size; i++) {
this.splitFilePathList.add(this.splitDirPath + File.separator + this.fileName + ".temp" + i);
}
}

/**
* @Description: 切割文件 ,确定起始点
*/
public void split() {
long beginPos = 0;
long actualBlockSize = this.blockSize;

for (int i = 0; i < this.size; i++) {
// 当最后一块的大小比分块的大小小的时候,实际大小为 总长度-起点
if (this.fileLength - beginPos <= this.blockSize) {
actualBlockSize = this.fileLength - beginPos;
}

splitDetil(i, beginPos, actualBlockSize);
// 起点 = 上一次的结尾 + 实际读取的长度
beginPos += actualBlockSize;
}
}

/**
* @Description: 切割文件的具体实现方法
*/
public void splitDetil(int index, long beginPos, long actualBlockSize) {
// 创建源文件
File src = new File(this.filePath);
File desc = new File(this.splitFilePathList.get(index));

RandomAccessFile raf = null;
BufferedOutputStream bos = null;
try {
// 设置只读读取
raf = new RandomAccessFile(src, "r");
bos = new BufferedOutputStream(new FileOutputStream(desc));

// 读取文件
raf.seek(beginPos);

// 缓冲
byte[] flush = new byte[1024];
// 记录每次读取的长度
int len = 0;
while (-1 != (len = raf.read(flush))) {
if ((actualBlockSize - len) > 0) {
bos.write(flush, 0, len);
actualBlockSize -= len;
} else {
// 写出最后一块后关闭循环
bos.write(flush, 0, (int) actualBlockSize);
break;
}
}

bos.flush();

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
raf.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

/**
* @Description: 文件合并
* @param: mergeFilePath 合并后的文件位置
*/
public void merge(String mergeFilePath) {
File dest = new File(mergeFilePath);
if (mergeFilePath == null) {
return;
}
// 目标文件不存在则创建
if (!new File(dest.getParent()).exists()) {
new File(dest.getParent()).mkdirs();
}

BufferedOutputStream bos = null;
BufferedInputStream bis = null;
try {
// 此处是追加,因为是文件合并
bos = new BufferedOutputStream(new FileOutputStream(dest, true));
for (int i = 0; i < this.size; i++) {

bis = new BufferedInputStream(new FileInputStream(new File(this.splitFilePathList.get(i))));

byte[] flush = new byte[1024];
int len = 0;
while (-1 != (len = bis.read(flush))) {
bos.write(flush, 0, len);
}

bos.flush();
bis.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

public static void main(String[] args) {
String fileName = "测试.pdf";
String basicPath = "C:\\Users\\Admin\\Downloads\\";
String filePath = basicPath + fileName;//目标文件名路径
String splitDirPath = basicPath + "\\split";//分割文件夹路径
String mergeFilePath = basicPath + "\\merge\\" + fileName;//合并文件路径
int blockSize = 1024 * 1024;//1MB大小分割
SplitFileDemo splitFileDemo = new SplitFileDemo(filePath, blockSize, splitDirPath);
splitFileDemo.split();//分割文件
splitFileDemo.merge(mergeFilePath);//合并文件
}
}
0%