文件分割的基本思想是将文件按着指定的大小从外存读到内存后,再将每块写入单独的、新建的子文件中。
这里要注意,比如你指定的文件分割后每个子文件的大小是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; } }