2013-04-27 4 views
1

Привет, Я работаю над проектом по написанию собственного кодирования хаффмана. В настоящее время у меня возникают проблемы с записью двоичных файлов 1 и 0 в выходной файл. Он работает с меньшими входными файлами, но для очень больших файлов он ничего не записывает в выходной файл. Метод, ответственный за запись, - это метод compress. Любая помощь будет оценена по достоинству. Спасибо!Запись больших двоичных данных в файл

package proj3; 

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.LinkedHashMap; 
import java.util.Map; 
import java.util.Scanner; 
import java.util.PriorityQueue; 

public class Project3 { 

//variables for PriorityQueue and Huffman Tree 
private static PriorityQueue<BinaryNode<Character>> queue; 
private static BinaryNode<Character> huffTree; 
private static Map<Character, String> table = new LinkedHashMap<Character, String>(); 

/** 
* Method for creating Huffman Tree 
* @param counts Map that contains all characters and their frequencies 
* @return the Huffman Tree 
*/ 
public static BinaryNode<Character> makeTree(Map<Character, Integer> counts) 
{ 
    queue = new PriorityQueue<BinaryNode<Character>>(); 

    for(Character c : counts.keySet()) 
    { 
     BinaryNode<Character> tree = new BinaryNode<Character>(c, counts.get(c), null, null); 
     queue.add(tree); 
    } 

    while(!queue.isEmpty()) 
    { 
     if(queue.size() >= 2) 
     { 
      BinaryNode<Character> n1 = queue.remove(); 
      BinaryNode<Character> n2 = queue.remove(); 
      Integer weight = n1.getFreq() + n2.getFreq(); 
      huffTree = new BinaryNode<Character>(null, weight, n1, n2); 
      queue.add(huffTree); 
     } 
     if(queue.size() == 1) 
     { 
      return queue.remove(); 
     } 
    } 
    return huffTree; 
} 

public static void encode(BinaryNode<Character> node, String s) 
{ 
    if(!node.isLeaf()) 
    { 
     encode(node.getLeft(), s + "0"); 
     encode(node.getRight(), s + "1"); 
    } 
    else 
    { 
     table.put(node.getElement(), s); 
    } 
} 

public static void compress(String in, String out) throws IOException 
{ 
    try 
    { 
     File outFile = new File(out); 
     FileOutputStream compressedFile = new FileOutputStream(outFile); 
     Scanner infile = new Scanner(new FileInputStream(in)); 
     while(infile.hasNext()) 
     { 
      infile.useDelimiter(""); 
      String str = infile.next(); 
      Character character = str.charAt(0); 
      for(Character c : table.keySet()) 
      { 
       if(c == character){ 
        compressedFile.write(table.get(c).getBytes()); 
        compressedFile.flush(); 
       } 
      } 
     } 
     for(Byte b : table.get('^').getBytes()) 
     { 
      compressedFile.write(b); 
     } 
     infile.close(); 
     compressedFile.close(); 
    } 
    catch (FileNotFoundException e) 
    { 
     System.err.println("File not found."); 
     e.printStackTrace(); 
    } 
} 

public static void decompress(String s) 
{ 

} 

public static void printEncodings(Map<Character, String> m) 
{ 
    ArrayList<Character> chars = new ArrayList<Character>(); 

    System.out.println("Character Encodings"); 
    System.out.println("---------------------"); 
    for(Character c : m.keySet()) 
    { 
     chars.add(c); 
     Collections.sort(chars); 
    } 
    for(Character c : chars) 
    { 
     System.out.print(c + "\t" + m.get(c) + "\n"); 
    } 
    System.out.println(); 
    System.out.println("Total Characters: " + chars.size()); 
} 

/** 
* Method for creating map with character and its frequencies 
* @param s the file name to be opened 
* @return the Map containing characters and frequencies 
*/ 
public static Map<Character, Integer> charCount(String s){ 

    Map<Character, Integer> counts = new LinkedHashMap<Character, Integer>(); 
    ArrayList<Character> chars = new ArrayList<Character>(); 

    try { 
     Scanner file = new Scanner(new FileInputStream(s)); 
     while(file.hasNext()){ 
      file.useDelimiter(""); 
      String str = file.next(); 
      Character c = str.charAt(0); 
      if(counts.containsKey(c)){ 
       counts.put(c, counts.get(c) + 1); 
      } 
      else{ 
       counts.put(c, 1); 
      } 
     } 
     counts.put('^', 1); 
     System.out.println("Character Frequencies"); 
     System.out.println("---------------------"); 
     for(Character c : counts.keySet()) 
     { 
      chars.add(c); 
      Collections.sort(chars); 
     } 
     for(Character c : chars){ 
      System.out.println(c + "\t" + counts.get(c)); 
     } 
     System.out.println(); 
     System.out.println("Total characters: " + chars.size() + "\n"); 
     file.close(); 
    } 
    catch (FileNotFoundException e) { 
     System.err.println("File not found."); 
     System.exit(0); 
    } 
    return counts; 
} 

public static void main(String[] args){ 

    if(args.length != 3) 
    { 
     throw new IllegalArgumentException("Invalid number of arguments."); 
    } 
    encode(makeTree(charCount(args[0])), ""); 
    printEncodings(table); 
    try { 
     compress(args[0], args[1]); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

} 
+1

делает отделку программы? Вы прошли через программу, чтобы узнать, что она делает? –

+0

Да, он распечатывает все правильные частоты символов и таблицу кодирования – somtingwong

+0

Это пустой файл, когда записаны большие данные? – Kowser

ответ

0

Я уверен, что вы столкнулись с проблемой производительности/памяти в методе compress(). Кодировки печатаются в основном в вашем основном методе, но я считаю, что выход файла застрянет. Я могу видеть, по крайней мере, три возможности для оптимизации в коде:

  1. Вы используете Scanner для чтения входного файла символ на гольца, но не использовать какие-либо возможности синтаксического анализа, предоставляемые сканером. Попробуйте вместо этого использовать InputStreamReader.

  2. Вы перебираете набор ключей в таблице Хаффмана и проверяете равенство. Вы можете просто использовать текущий символ, чтобы получить строку, на которую она сопоставлена, и опустить цикл.

  3. Вам не нужно зацикливать массив байтов, чтобы записать его в выходной файл. Метод write() FileOutputStream может принимать в качестве параметра целый массив байтов.

С моими скромными навыками Java я бы скорее использовал его так или иначе как внизу; Пожалуйста, обратите внимание, что это непроверенный код, так как я не ваш класс BinaryNode:

public static void compress(String in, String out) throws IOException 
{ 
    try 
     { 
      File outFile = new File(out); 
      FileOutputStream compressedFile = new FileOutputStream(outFile); 

      // 1. Use a Reader instead of a Scanner; 
      // make sure to use the correct charset 
      FileInputStream fis= new FileInputStream(in); 
      Reader reader = new InputStreamReader(fis,   
       Charset.forName("US-ASCII")); 

      // use BufferedReader for even better performance 
      Reader bufferedReader = new BufferedReader(reader); 

      int r; 
      while ((r = bufferedReader.read()) != -1) { 
       char ch= (char) r; 

       // 2. Get the string for this character directly instead of 
       // looping the keySet and checking for equivalence 
       String s= table.get(ch); 
       if (s != null) { 
        // 3. Write entire array of bytes instead of 
        // looping and writing bytes one by one 
        compressedFile.write(s.getBytes()); 
       } 
      } 
      fis.close(); 
      compressedFile.close(); 
     } 
    ... 
+0

Клянусь, я поставил именно то, что вы написали, но он все еще не работает ..... Возможно ли, что другие части моего кода настолько неэффективны, что он не работает для больших файлов? – somtingwong

+0

Я думаю, что нет, остальное должно быть достаточно эффективным. проверьте следующее: 1) Вы бросаете, когда args.length! = 3, но используете только 2 аргумента в вашем коде. 2) Указывает ли args [0] на существующий файл? Существуют ли все каталоги в args [1]? 3) Вы очистили/перекомпилировали проект после внесения изменений в код? 4) Использует ли BinaryNode java.lang.comparable (необходимо для PriorityQueue)? 5) Запустил ли ваш код в режиме отладки и проверил любые журналы или выходы консоли на наличие ошибок/стеков? 6) Получается ли выходной файл с 0 КБ или он отсутствует? 7) Закончился ли ваш код? – Marcellus

0

Вполне вероятно, что вам нужно позвонить compressedFile.flush()

Улучшить как этот

  if(c == character){ 
       compressedFile.write(table.get(c).getBytes()); 
       compressedFile.flush(); 
      } 

Дополнительно рассмотреть возможность использования try/catch. Улучшит целостность реализации.

+0

Нет, извините, он все еще ничего не пишет :( – somtingwong

+0

@ user1813076: обновлено снова – Kowser

+0

Простите еще раз, но я уверен, что обновляюсь точно так же, как вы написали, но он все еще не работает .... – somtingwong