1 package org.testng.reporters; 2 3 import java.io.BufferedWriter; 4 import java.io.File; 5 import java.io.FileReader; 6 import java.io.FileWriter; 7 import java.io.IOException; 8 import java.io.Reader; 9 import java.io.StringReader; 10 import java.io.Writer; 11 import java.util.Random; 12 13 /** 14 * A string buffer that flushes its content to a temporary file whenever the internal 15 * string buffer becomes larger than MAX. If the buffer never reaches that size, no file 16 * is ever created and everything happens in memory, so the overhead compared to 17 * StringBuffer/StringBuilder is minimal. 18 * 19 * Note: calling toString() will force the entire string to be loaded in memory, use 20 * toWriter() if you need to avoid this. 21 * 22 * This class is not multi thread safe. 23 * 24 * @author Cedric Beust <cedric@beust.com> 25 * 26 * @since Nov 9, 2012 27 */ 28 public class FileStringBuffer implements IBuffer { 29 private static int MAX = 100000; 30 private static final boolean VERBOSE = System.getProperty("fileStringBuffer") != null; 31 32 private File m_file; 33 private StringBuilder m_sb = new StringBuilder(); 34 private final int m_maxCharacters; 35 FileStringBuffer()36 public FileStringBuffer() { 37 this(MAX); 38 } 39 FileStringBuffer(int maxCharacters)40 public FileStringBuffer(int maxCharacters) { 41 m_maxCharacters = maxCharacters; 42 } 43 44 @Override append(CharSequence s)45 public FileStringBuffer append(CharSequence s) { 46 if (s == null) { 47 throw new IllegalArgumentException("CharSequence (Argument 0 of FileStringBuffer#append) should not be null"); 48 } 49 // m_sb.append(s); 50 if (m_sb.length() > m_maxCharacters) { 51 flushToFile(); 52 } 53 if (s.length() < MAX) { 54 // Small string, add it to our internal buffer 55 m_sb.append(s); 56 } else { 57 // Big string, add it to the temporary file directly 58 flushToFile(); 59 try { 60 copy(new StringReader(s.toString()), new FileWriter(m_file, true /* append */)); 61 } catch (IOException e) { 62 e.printStackTrace(); 63 } 64 } 65 return this; 66 } 67 68 @Override toWriter(Writer fw)69 public void toWriter(Writer fw) { 70 if (fw == null) { 71 throw new IllegalArgumentException("Writer (Argument 0 of FileStringBuffer#toWriter) should not be null"); 72 } 73 try { 74 BufferedWriter bw = new BufferedWriter(fw); 75 if (m_file == null) { 76 bw.write(m_sb.toString()); 77 bw.close(); 78 } else { 79 flushToFile(); 80 copy(new FileReader(m_file), bw); 81 } 82 } catch(IOException ex) { 83 ex.printStackTrace(); 84 } 85 } 86 copy(Reader input, Writer output)87 private static void copy(Reader input, Writer output) 88 throws IOException { 89 char[] buf = new char[MAX]; 90 while (true) { 91 int length = input.read(buf); 92 if (length < 0) break; 93 output.write(buf, 0, length); 94 } 95 96 try { 97 input.close(); 98 } catch (IOException ignore) { 99 } 100 try { 101 output.close(); 102 } catch (IOException ignore) { 103 } 104 } 105 flushToFile()106 private void flushToFile() { 107 if (m_sb.length() == 0) return; 108 109 if (m_file == null) { 110 try { 111 m_file = File.createTempFile("testng", "fileStringBuffer"); 112 m_file.deleteOnExit(); 113 p("Created temp file " + m_file); 114 } catch (IOException e) { 115 e.printStackTrace(); 116 } 117 } 118 119 p("Size " + m_sb.length() + ", flushing to " + m_file); 120 try (FileWriter fw = new FileWriter(m_file, true /* append */)) { 121 fw.append(m_sb); 122 } catch (IOException e) { 123 e.printStackTrace(); 124 } 125 m_sb = new StringBuilder(); 126 } 127 p(String s)128 private static void p(String s) { 129 if (VERBOSE) { 130 System.out.println("[FileStringBuffer] " + s); 131 } 132 } 133 134 @Override toString()135 public String toString() { 136 String result = null; 137 if (m_file != null) { 138 flushToFile(); 139 try { 140 result = Files.readFile(m_file); 141 } catch (IOException e) { 142 e.printStackTrace(); 143 } 144 } else { 145 result = m_sb.toString(); 146 } 147 return result; 148 } 149 save(File expected, String s)150 private static void save(File expected, String s) throws IOException { 151 expected.delete(); 152 try (FileWriter expectedWriter = new FileWriter(expected)) { 153 expectedWriter.append(s); 154 } 155 } 156 main(String[] args)157 public static void main(String[] args) throws IOException { 158 String s = "abcdefghijklmnopqrstuvwxyz"; 159 FileStringBuffer fsb = new FileStringBuffer(10); 160 StringBuilder control = new StringBuilder(); 161 Random r = new Random(); 162 for (int i = 0; i < 1000; i++) { 163 int start = Math.abs(r.nextInt() % 26); 164 int length = Math.abs(r.nextInt() % (26 - start)); 165 String fragment = s.substring(start, start + length); 166 p("... Appending " + fragment); 167 fsb.append(fragment); 168 control.append(fragment); 169 } 170 171 File expected = new File("/tmp/expected"); 172 expected.delete(); 173 FileWriter expectedWriter = new FileWriter(expected); 174 expectedWriter.append(control); 175 expectedWriter.close(); 176 177 File actual = new File("/tmp/actual"); 178 actual.delete(); 179 FileWriter actualWriter = new FileWriter(actual); 180 fsb.toWriter(actualWriter); 181 actualWriter.close(); 182 // Assert.assertEquals(fsb.toString(), control.toString()); 183 } 184 185 } 186