文件分割的基本思想是将文件按着指定的大小从外存读到内存后,再将每块写入单独的、新建的子文件中。
这里要注意,比如你指定的文件分割后每个子文件的大小是1.44MB,那么把原文件从流中读出来时(实际上是读到一个字节数组中)可以一次就读1.44MB,也可以每次就读1024KB,分多次读出来。
还有,要注意对文件结尾的处理。因为不可能每次就那么凑巧原文件的大小刚好能被每块的大小整除。所以,最后一块要写入它的实际大小。
至于子文件的命名,子文件的扩展名最好不要与源文件相同,否则用户体验是很不好的,最好设计你自己的扩展名,等合并后,再获取原来的扩展名。
import javax.swing.*;
/*程序主窗口类*/
public class MainFrame extends JFrame {
private static final long serialVersionUID = 1L;
private JTabbedPane tabs = new JTabbedPane();
private FCPanel fcp = new FCPanel();
private FMPanel fmp = new FMPanel();
{
tabs.add("File Cut", this.fcp);
tabs.add("File Merge", this.fmp);
}
public MainFrame() {
super("Super File Cutter by LiuShuai");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setBounds(390, 100, 595, 545);
this.setResizable(false);
this.add(tabs);
this.setVisible(true);
}
public static void main(String[] args) {
new MainFrame();
}
}
import javax.swing.*;
/*文件切割面板*/
public class FCPanel extends JPanel {
private static final long serialVersionUID = 2L;
private JPanel sp1 = new JPanel();/*子面板*/
private JPanel sp2 = new JPanel();
private JPanel sp3 = new JPanel();
private JPanel sp4 = new JPanel();
private JPanel sp5 = new JPanel();
private JPanel sp6 = new JPanel();
private JPanel sp7 = new JPanel();
protected JLabel lb1 = new JLabel("File Name:");
protected JTextField tf1 = new JTextField(30);
protected JButton buttonChooser1 = new JButton("...");
{
buttonChooser1.setToolTipText("单击此按钮选择要切割的文件。");
tf1.setEditable(false);
}
protected JLabel lb2 = new JLabel("File Size:");
protected JTextField tf2 = new JTextField(34);
{
tf2.setEditable(false);
}
protected JLabel lb3 = new JLabel("Block Size:");
protected JRadioButton rb1 = new JRadioButton("1.44MB");
protected JRadioButton rb2 = new JRadioButton("1.2MB");
protected JRadioButton rb3 = new JRadioButton("720KB");
protected JRadioButton rb4 = new JRadioButton("360KB");
protected JRadioButton rb5 = new JRadioButton("Self Defined:");
protected JTextField tf3 = new JTextField(8);
protected JLabel lb4 = new JLabel("KB");
protected ButtonGroup group = new ButtonGroup();
{
group.add(rb1);
group.add(rb2);
group.add(rb3);
group.add(rb4);
group.add(rb5);
rb1.setEnabled(false);
rb2.setEnabled(false);
rb3.setEnabled(false);
rb4.setEnabled(false);
rb5.setEnabled(false);
tf3.setEnabled(false);
tf3.setToolTipText("注意,你只能填写小于2147483647的正数,否则数据会溢出!!");
}
protected JLabel lb5 = new JLabel("Number of Blocks:");
protected JTextField tf4 = new JTextField(8);
{
tf4.setEditable(false);
}
protected JLabel lb6 = new JLabel("Target Position:");
protected JTextField tf5 = new JTextField(20);
protected JButton buttonChooser2 = new JButton("...");
{
buttonChooser2.setToolTipText("单击此按钮选择切割后的子文件存放路径。");
tf5.setEditable(false);
}
protected JButton buttonStartCut = new JButton("Start Cutting");
protected JProgressBar pb = new JProgressBar();
{
pb.setStringPainted(true);
}
protected ImageIcon icon = new ImageIcon(
".//abc.jpg");
protected JLabel lb7 = new JLabel(icon);
protected CutControl cutControl = new CutControl(this);/*cutControl实现了监听器的一些接口*/
public FCPanel() {
addSp1();
addSp2();
addSp3();
addSp4();
addSp5();
addSp6();
addSp7();
this.add(sp1);/*将子面板加入面板*/
this.add(sp2);
this.add(sp3);
this.add(sp4);
this.add(sp5);
this.add(sp6);
this.add(sp7);
this.buttonChooser1.addActionListener(cutControl);/*为控件添加监听器*/
this.rb1.addFocusListener(cutControl);
this.rb2.addFocusListener(cutControl);
this.rb3.addFocusListener(cutControl);
this.rb4.addFocusListener(cutControl);
this.rb5.addFocusListener(cutControl);
this.tf3.addFocusListener(cutControl);
this.buttonChooser2.addActionListener(cutControl);
this.buttonStartCut.addActionListener(cutControl);
}
private void addSp1() {/*将控件加入子面板*/
this.sp1.add(this.lb1);
this.sp1.add(this.tf1);
this.sp1.add(this.buttonChooser1);
}
private void addSp2() {
this.sp2.add(this.lb2);
this.sp2.add(this.tf2);
}
private void addSp3() {
this.sp3.add(this.lb3);
this.sp3.add(this.rb1);
this.sp3.add(this.rb2);
this.sp3.add(this.rb3);
this.sp3.add(this.rb4);
this.sp3.add(this.rb5);
this.sp3.add(this.tf3);
this.sp3.add(this.lb4);
}
private void addSp4() {
this.sp4.add(this.lb5);
this.sp4.add(this.tf4);
}
private void addSp5() {
this.sp5.add(this.lb6);
this.sp5.add(this.tf5);
this.sp5.add(this.buttonChooser2);
}
private void addSp6() {
this.sp6.add(this.buttonStartCut);
this.sp6.add(this.pb);
}
private void addSp7() {
this.sp7.add(this.lb7);
}
}
import javax.swing.*;
/*文件合并面板*/
public class FMPanel extends JPanel {
private static final long serialVersionUID = 3L;
private JPanel sp1 = new JPanel();
private JPanel sp2 = new JPanel();
private JPanel sp3 = new JPanel();
private JPanel sp4 = new JPanel();
private JPanel sp5 = new JPanel();
private JPanel sp6 = new JPanel();
protected JLabel lb1 = new JLabel("File Name:");
protected JTextField tf1 = new JTextField(30);
protected JButton buttonChooser1 = new JButton("...");
{
tf1.setEditable(false);
}
protected JLabel lb2 = new JLabel("File to be merged:");
protected JTextArea ta = new JTextArea(10, 30);
protected JScrollPane sp = new JScrollPane(ta,
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
{
ta.setEditable(false);
ta.setLineWrap(true);
ta.setWrapStyleWord(true);
ta.setToolTipText("请确保每个文件的大小在2047MB以内,否则后果自负!");
}
protected JLabel lb3 = new JLabel("Number of files:");
protected JTextField tf2 = new JTextField(15);
protected JButton buttonRemove = new JButton("Remove");
protected JButton buttonClear = new JButton("Clear");
{
tf2.setEditable(false);
}
protected JLabel lb4 = new JLabel("Target Position:");
protected JTextField tf3 = new JTextField(24);
protected JButton buttonChooser2 = new JButton("...");
{
tf3.setEditable(false);
}
protected JButton buttonStartMerging = new JButton("Start Merging");
protected JProgressBar pb = new JProgressBar();
{
pb.setStringPainted(true);
}
protected ImageIcon icon = new ImageIcon(
".//b.jpg");
protected JLabel lb5 = new JLabel(icon);
protected MergeControl mergeControl = new MergeControl(this);
public FMPanel() {
addSp1();
addSp2();
addSp3();
addSp4();
addSp5();
addSp6();
this.add(sp1);
this.add(sp2);
this.add(sp3);
this.add(sp4);
this.add(sp5);
this.add(sp6);
this.buttonChooser1.addActionListener(mergeControl);/*为控件加监听器*/
this.buttonChooser2.addActionListener(mergeControl);
this.buttonRemove.addActionListener(mergeControl);
this.buttonClear.addActionListener(mergeControl);
this.buttonStartMerging.addActionListener(mergeControl);
}
private void addSp1() {
this.sp1.add(this.lb1);
this.sp1.add(this.tf1);
this.sp1.add(this.buttonChooser1);
}
private void addSp2() {
this.sp2.add(this.lb2);
this.sp2.add(this.sp);
}
private void addSp3() {
this.sp3.add(this.lb3);
this.sp3.add(this.tf2);
this.sp3.add(this.buttonRemove); // 可以理解为删除最后一个添加的文件
this.sp3.add(this.buttonClear); // 全部删除
}
private void addSp4() {
this.sp4.add(this.lb4);
this.sp4.add(this.tf3);
this.sp4.add(this.buttonChooser2);
}
private void addSp5() {
this.sp5.add(this.buttonStartMerging);
this.sp5.add(this.pb);
}
private void addSp6() {
this.sp6.add(this.lb5);
}
}
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
public class CutControl implements ActionListener, FocusListener, Runnable {
private FCPanel fcPanel = null;/*面板的实例,要对程序“文件切割”的面板进行一些操作*/
private File sourceFile = null;/*要切割的文件*/
private File targetFile = null;/*切割后的目标位置*/
private JFileChooser fileChooser1 = new JFileChooser(new File("E:/"));/*文件选择对话框*/
private JFileChooser fileChooser2 = new JFileChooser(new File("E:/"));
{
fileChooser2.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);/*设置文件选择对话框2只显示目录不显示文件*/
}
private long blockNumbers = 0;/*块数*/
// private Thread pbThread = new Thread(this);
public CutControl(FCPanel fcPanel) {/*构造函数*/
this.fcPanel = fcPanel;
}
private byte[] creatByteArray() {/*根据每块大小建立一个字节数组*/
if (fcPanel.rb1.isSelected()) {
return new byte[1509949];
} else if (fcPanel.rb2.isSelected()) {
return new byte[1258291];
} else if (fcPanel.rb3.isSelected()) {
return new byte[737280];
} else if (fcPanel.rb4.isSelected()) {
return new byte[368640];
} else if (fcPanel.rb5.isSelected()) {
int temp = 0;
try {
temp = Integer.parseInt(fcPanel.tf3.getText()) * 1024;
} catch (Exception e) {
JOptionPane.showMessageDialog(fcPanel, "请正确地设置子文件大小!");
return null;
}
return new byte[temp];
} else {
JOptionPane.showMessageDialog(fcPanel, "请正确地设置子文件大小!");
return null;
}
}
private String creatSubFileName(int a) {/*为切割后的子文件命名*/
if (a <= 9) {
return "00" + a;
} else if (a <= 99) {
return "0" + a;
} else
return "" + a;
}
@Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == fcPanel.buttonChooser1) {/*选择要切割的文件*/
int result = fileChooser1.showOpenDialog(fcPanel);
if (result == JFileChooser.APPROVE_OPTION) {
sourceFile = fileChooser1.getSelectedFile();/*存到sourceFile里面*/
fcPanel.tf1.setText(sourceFile.getAbsolutePath());
fcPanel.tf2.setText((sourceFile.length()) + " B");
fcPanel.rb1.setEnabled(true);
fcPanel.rb2.setEnabled(true);
fcPanel.rb3.setEnabled(true);
fcPanel.rb4.setEnabled(true);
fcPanel.rb5.setEnabled(true);
}
}
else if (source == fcPanel.buttonChooser2) {/*选择子文件的存放路径*/
int result = fileChooser2.showSaveDialog(fcPanel);
if (result == JFileChooser.APPROVE_OPTION) {
targetFile = fileChooser2.getSelectedFile();/*存到targetFile里面*/
fcPanel.tf5.setText(targetFile.getAbsolutePath());
}
}
else if (source == fcPanel.buttonStartCut) {/*点击开始切割按钮的事件处理*/
try {
byte[] tempByte = null;
if (fcPanel.tf1.getText() == null
|| fcPanel.tf1.getText().equals("")) {
JOptionPane.showMessageDialog(null, "请先选择要切割的文件!");
return;
}
if ((tempByte = creatByteArray()) == null) {
return;
}
if (fcPanel.tf5.getText() == null
|| fcPanel.tf5.getText().equals("")) {
JOptionPane.showMessageDialog(null, "请先选择目标文件的存放路径!");
return;
}
Thread pbThread = new Thread(this);/*开一个刷新进度条的线程*/
pbThread.start();
FileInputStream fis = new FileInputStream(sourceFile);
FileOutputStream fos = null;
File tempFile = null;
int flag = 0;
int iNameCount = 1;
this.progressBarPositon = 0;
String tempName = sourceFile.getName();
while ((flag = fis.read(tempByte)) > 0) {/*循环从源文件中读取数据存入到字节数组里*/
if (flag < tempByte.length) { /*对文件尾巴的处理*/
byte[] tempByte1 = new byte[flag];
for (int i = 0; i < flag; i++) {
tempByte1[i] = tempByte[i];
}
tempByte = tempByte1;
}
tempFile = new File(fcPanel.tf5.getText() + "/" /*新建立一个子文件的实例*/
+ tempName.substring(0, tempName.lastIndexOf("."))
+ "_" + creatSubFileName(iNameCount) + "."
+ tempName.substring(tempName.lastIndexOf(".") + 1));
System.out.println(tempFile.getName());
if (!tempFile.exists()) {
tempFile.createNewFile();/*创建子文件*/
}
fos = new FileOutputStream(tempFile);
fos.write(tempByte);/*将读出来的字节数组写入新的子文件*/
progressBarPositon = (int) (100 * ((float) iNameCount / (float) blockNumbers));/*更新进度条的值*/
iNameCount++;
fos.close();/*关闭流*/
}
progressBarPositon = 100;/*到最后循环出来时把进度条的值设置为100*/
fis.close();/*关闭流*/
} catch (FileNotFoundException e1) {
JOptionPane.showMessageDialog(null, "文件木有找到,请确定文件是否被删除!");
e1.printStackTrace();
return ;
} catch (IOException e1) {
JOptionPane.showMessageDialog(null, "文件读写发生异常,请重新启动程序!");
e1.printStackTrace();
return ;
}
}
}
@Override
public void focusGained(FocusEvent e) {/*对RadioButton得到焦点事件的处理,点击每个块大小时能计算出要分多少块*/
Object source = e.getSource();
String temp = fcPanel.tf2.getText();
if (source == fcPanel.rb1) {
blockNumbers = Long.parseLong(temp.substring(0, temp.length() - 2)) / 1509949;
fcPanel.tf4.setText("≥ " + blockNumbers + " blocks");
} else if (source == fcPanel.rb2) {
blockNumbers = Long.parseLong(temp.substring(0, temp.length() - 2)) / 1258291;
fcPanel.tf4.setText("≥ " + blockNumbers + " blocks");
} else if (source == fcPanel.rb3) {
blockNumbers = (Long
.parseLong(temp.substring(0, temp.length() - 2)) / 737280);
fcPanel.tf4.setText("≥ " + blockNumbers + " blocks");
} else if (source == fcPanel.rb4) {
blockNumbers = (Long
.parseLong(temp.substring(0, temp.length() - 2)) / 368640);
fcPanel.tf4.setText("≥ " + blockNumbers + " blocks");
} else if (source == fcPanel.rb5) {
if (fcPanel.tf3.isEnabled() == false
|| fcPanel.tf3.getText() == null
|| fcPanel.tf3.getText().equals("")) {
fcPanel.tf3.setEnabled(true);
} else {
try {
blockNumbers = (Long.parseLong(temp.substring(0,
temp.length() - 2)) / (Long.parseLong(fcPanel.tf3
.getText()) * 1024L));
fcPanel.tf4.setText("≥ " + blockNumbers + " blocks");
} catch (Exception e1) {
JOptionPane.showMessageDialog(null, "请正确地设置每块文件的大小!");
}
}
}
}
@Override
public void focusLost(FocusEvent e) {/*自己输入块的大小时文本框失去焦点后计算要分多少块*/
Object source = e.getSource();
String temp = fcPanel.tf2.getText();
if (source == fcPanel.tf3) {
if (fcPanel.tf3.getText().equals("")
|| fcPanel.tf3.getText() == null) {
fcPanel.tf4.setText("");
return;
} else {
try {
blockNumbers = (Long.parseLong(temp.substring(0,
temp.length() - 2)) / (Long.parseLong(fcPanel.tf3
.getText()) * 1024L));
fcPanel.tf4.setText("≥ " + blockNumbers + " blocks");
} catch (Exception e1) {
JOptionPane.showMessageDialog(null,
"Plese set right block size!");
}
}
}
}
private int progressBarPositon = 0;/*进度条位置变量*/
{
// synchronized (progressBarPositon) {}
}
@Override
public void run() {/*刷新进度条*/
fcPanel.pb.setMinimum(0);
fcPanel.pb.setMaximum(100);
Dimension d = fcPanel.pb.getSize();
Rectangle rect = new Rectangle(0, 0, d.width, d.height);
while (true) {
fcPanel.pb.setValue(progressBarPositon);
fcPanel.pb.paintImmediately(rect);
System.out.println(progressBarPositon);
if (progressBarPositon == 100) {
fcPanel.pb.setValue(progressBarPositon);
break;
}
}
JOptionPane.showMessageDialog(null, "文件" + "“" + sourceFile.getName()
+ "”" + "切割完毕!");
return;
}
}
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.*;
import java.io.*;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
public class MergeControl implements ActionListener, Runnable {
protected FMPanel fmPanel = null;
private JFileChooser fileChooser1 = new JFileChooser(new File("E:/"));
private JFileChooser fileChooser2 = new JFileChooser(new File("E:/"));
{
fileChooser1.setMultiSelectionEnabled(true);
fileChooser2.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
}
private File[] sourceFiles = null;
private File targetFile = null;
// private Thread pbThread = new Thread(this);
/*
* private byte[] creatByteArray(File[] files) { try { int maxLengthOfFiles
* = 0; for (int i = 0; i < files.length; i++) { if (files[i] == null)
* continue; if (files[i].length() > maxLengthOfFiles) { maxLengthOfFiles =
* (int) files[i].length(); } } return new byte[maxLengthOfFiles]; } catch
* (Exception e) { return null; } }
*/
public MergeControl(FMPanel fmPanel) {
this.fmPanel = fmPanel;
}
@Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == fmPanel.buttonChooser1) {
int result = fileChooser1.showOpenDialog(fmPanel);
if (result == JFileChooser.APPROVE_OPTION) {
sourceFiles = fileChooser1.getSelectedFiles();
fmPanel.tf1.setText(sourceFiles[0].getAbsolutePath()
+ " and so on...");
fmPanel.ta.setText("");
for (int i = 0; i < sourceFiles.length; i++) {
if (sourceFiles[i] != null)
fmPanel.ta.append(sourceFiles[i].getAbsolutePath()
+ "\n");
}
fmPanel.tf2.setText(sourceFiles.length + "");
}
}
else if (source == fmPanel.buttonRemove) {
String temp = fmPanel.ta.getSelectedText();
System.out.println(temp);
boolean flag = false;
if (temp == null) {
JOptionPane.showMessageDialog(null, "请先选择要删除的文件!");
return;
} else {
fmPanel.ta.setText("");
for (int i = 0; i < sourceFiles.length; i++) {
if (sourceFiles[i] == null) {
continue;
}
if (sourceFiles[i].getAbsolutePath().equals(temp)) {
sourceFiles[i] = null;
flag = true;
} else {
fmPanel.ta.append(sourceFiles[i].getAbsolutePath()
+ "\n");
}
}
if (!flag) {
JOptionPane.showMessageDialog(null,
"请正确地选择要删除的文件!");
return;
}
int iCount = 0;
for (int i = 0; i < sourceFiles.length; i++) {
if (sourceFiles[i] != null)
iCount++;
}
fmPanel.tf2.setText(iCount + "");
}
}
else if (source == fmPanel.buttonClear) {
if (fmPanel.tf1.getText() == null
|| fmPanel.tf1.getText().equals("")) {
JOptionPane.showMessageDialog(null, "请先选择要合并的文件!");
return;
}
for (int i = 0; i < sourceFiles.length; i++) {
sourceFiles[i] = null;
}
fmPanel.ta.setText("");
fmPanel.tf2.setText(0 + "");
}
else if (source == fmPanel.buttonChooser2) {
if (fmPanel.tf1.getText() == null
|| fmPanel.tf1.getText().equals("")) {
JOptionPane.showMessageDialog(null, "请先选择要合并的文件!");
return;
}
int result = fileChooser2.showSaveDialog(fmPanel);
if (result == JFileChooser.APPROVE_OPTION) {
targetFile = fileChooser2.getSelectedFile();
fmPanel.tf3.setText(targetFile.getAbsolutePath());
}
}
else if (source == fmPanel.buttonStartMerging) {/*开始合并*/
try {
if (fmPanel.tf1.getText() == null
|| fmPanel.tf1.getText().equals("")) {
JOptionPane.showMessageDialog(null, "请先选择要合并的文件!");
return;
}
if (fmPanel.tf3.getText() == null
|| fmPanel.tf3.getText().equals("")) {
JOptionPane.showMessageDialog(null, "请先选择目标文件的路径!");
return;
}
boolean flag = false;
String tempName = null;
for (File f : sourceFiles) {
if (f != null) {
flag = true;
tempName = f.getName();
break;
}
}
if (!flag) {
JOptionPane.showMessageDialog(null, "请重新选择要合并的文件!");
return;
}
@SuppressWarnings("unused")
int flag1 = 0;
FileInputStream fis = null;
FileOutputStream fos = null;
File tempFile = null;
byte[] tempByte = null;
/*
* if ((tempByte = creatByteArray(sourceFiles)) == null) {
* return; }
*/
Thread pbThread = new Thread(this);
pbThread.start();
tempFile = new File(fmPanel.tf3.getText() + "/"
+ tempName.substring(0, tempName.lastIndexOf("_"))
+ "_HaveMerged" + "."
+ tempName.substring(tempName.lastIndexOf(".") + 1));
if (!tempFile.exists()) {
tempFile.createNewFile();
}
fos = new FileOutputStream(tempFile, true);
int iCount = 0;
this.progressBarPosition = 0;
for (int i = 0; i < sourceFiles.length; i++) {
if (sourceFiles[i] == null)
continue;
fis = new FileInputStream(sourceFiles[i]);
try{
tempByte = new byte[(int) sourceFiles[i].length()];
}catch(Exception e1){
System.out.println("请选择小一点的文件!");
}
while ((flag1 = fis.read(tempByte)) > 0) {
fos.write(tempByte);
fos.flush();
}
System.out.println(sourceFiles[i].getName());
fis.close();
progressBarPosition = (int) (100 * ((float) iCount / (float) sourceFiles.length));
iCount++;
}
progressBarPosition = 100;
fos.close();
} catch (FileNotFoundException e1) {
JOptionPane.showMessageDialog(null, "文件没有找到!请确定文件没有被删除!!");
e1.printStackTrace();
return ;
} catch (IOException e2) {
JOptionPane.showMessageDialog(null, "文件读写出现异常,请重启系统!");
e2.printStackTrace();
return ;
}
}
}
private int progressBarPosition = 0;
@Override
public void run() {
fmPanel.pb.setMinimum(0);
fmPanel.pb.setMaximum(100);
Dimension d = fmPanel.pb.getSize();
Rectangle rect = new Rectangle(0, 0, d.width, d.height);
fmPanel.pb.setValue(0);
fmPanel.pb.paintImmediately(rect);
while (true) {
fmPanel.pb.setValue(progressBarPosition);
fmPanel.pb.paintImmediately(rect);
// System.out.println(progressBarPosition);
if (progressBarPosition == 100) {
fmPanel.pb.setValue(progressBarPosition);
break;
}
}
JOptionPane.showMessageDialog(null, "文件合并完毕!");
return;
}
}