source: release-kits/wirk3/ant-scripts/tasks/antelope/src/ise/antelope/tasks/SplitTask.java@ 15023

Last change on this file since 15023 was 15023, checked in by oranfry, 16 years ago

did the bulk of the work on wirk3

File size: 12.0 KB
Line 
1
2package ise.antelope.tasks;
3
4import java.io.*;
5
6import org.apache.tools.ant.*;
7import org.apache.tools.ant.taskdefs.*;
8
9/**
10 * This task is similar to the Unix/Linux split utility, it splits a file into
11 * a number of smaller pieces. It will also split a property value or a string.
12 *
13 * @author Dale Anson
14 * @version $Revision: 1.3 $
15 * @since Ant 1.6
16 */
17public class SplitTask extends Task {
18
19 private String prefix = "x";
20 private int bytes = -1;
21 private int lines = 1000;
22 private String value = null;
23 private File file = null;
24 private File outputDir = null;
25 private boolean failOnError = true;
26
27 /**
28 * Buffer size for read and write operations, default is 1 MB, but this is
29 * a user setting.
30 */
31 public int BUFFER_SIZE = 1024 * 1024;
32
33
34 /**
35 * The start of the file names to write. Files are named using this string,
36 * followed by a "." and a number, e.g. x.0, x.1, etc. The Unix/Linux split
37 * uses a letter scheme for the suffix, that is not supported here.
38 *
39 * Should the dot go away? If the user wants a dot, it could be part of this
40 * attribute. Right now, the dot is there, and there is no way for the user
41 * to make it go away.
42 *
43 * @param x The new prefix value
44 */
45 public void setPrefix( String x ) {
46 prefix = x;
47 }
48
49 /**
50 * Set the number of bytes per part. This is not a required parameter,
51 * the default is to use lines rather than bytes.
52 *
53 * Use bytes or lines, not both. In general, use bytes or size for binary
54 * files, lines for text files.
55 *
56 * @param b number of bytes per part.
57 */
58 public void setBytes( int b ) {
59 bytes = b;
60 lines = -1;
61 }
62
63 /**
64 * The linux split command allows modifiers: b for 512, k for 1K, m for 1
65 * Meg. Use this method for a similar effect. This is not a required
66 * parameter, the default is to use lines rather than size.
67 *
68 * Use bytes or lines, not both. In general, use bytes or size for binary
69 * files, lines for text files.
70 *
71 * @param b the number of bytes per part, with an optional modifier. If
72 * there is no modifier, treat same as setBytes(int). For example,
73 * setSize("100k") is the same as setBytes(100 * 1024). Note that the
74 * maximum size must be smaller than Integer.MAX_VALUE (2147483647).
75 */
76 public void setSize( String b ) {
77 try {
78 int size = calcSize(b);;
79 setBytes( size );
80 }
81 catch ( NumberFormatException e ) {
82 throw new BuildException( "Invalid size parameter: " + b );
83 }
84 }
85
86
87 /**
88 * Set how much memory to use as an internal buffer. The default internal
89 * buffer size is 1 MB.
90 *
91 * @param b the number of bytes per part, with an optional modifier. If
92 * there is no modifier, treat same as setBytes(int). For example,
93 * setSize("100k") is the same as setBytes(100 * 1024). Note that the
94 * maximum size must be smaller than Integer.MAX_VALUE (2147483647).
95 */
96 public void setBuffersize(String b) {
97 try {
98 int size = calcSize(b);;
99 BUFFER_SIZE = size;
100 }
101 catch ( NumberFormatException e ) {
102 throw new BuildException( "Invalid buffer size parameter: " + b );
103 }
104 }
105
106 /**
107 * Set the number of lines per part, default is 1000. This is not a required
108 * parameter, but is the default setting for splitting.
109 *
110 * Use bytes or lines, not both. In general, use bytes or size for binary
111 * files, lines for text files.
112 *
113 * @param x The number of lines per part.
114 */
115 public void setLines( int x ) {
116 lines = x;
117 bytes = -1;
118 }
119
120 /**
121 * Split the text value of the given property.
122 *
123 * One of property, value, or file are required.
124 *
125 * @param p the name of the property whose value will be split.
126 */
127 public void setProperty( String p ) {
128 String v = getProject().getProperty( p );
129 if ( v == null || v.equals( "" ) )
130 throw new BuildException( "Property " + p + " has no value." );
131 setValue( v );
132 }
133
134 /**
135 * Split the given string.
136 *
137 * One of property, value, or file are required.
138 *
139 * @param v a string
140 */
141 public void setValue( String v ) {
142 if ( v == null || v.equals( "" ) )
143 throw new BuildException( "Value is null or empty." );
144 value = v;
145 }
146
147 /**
148 * Split the contents of the given file.
149 *
150 * One of property, value, or file are required.
151 *
152 * @param f the name of the file
153 */
154 public void setFile( File f ) {
155 file = f;
156 }
157
158 /**
159 * Where to put the parts. If file has been set and output directory has not
160 * been set, output to directory containing file.
161 *
162 * @param d the output directory
163 */
164 public void setOutputdir( File d ) {
165 outputDir = d;
166 }
167
168 /**
169 * Determines whether the build should fail if there is an error. Default is
170 * true.
171 *
172 * @param fail true or false
173 */
174 public void setFailonerror( boolean fail ) {
175 failOnError = fail;
176 }
177
178
179 /**
180 * Split the given property, value, or file into pieces.
181 *
182 * @exception BuildException only if failOnError is true
183 */
184 public void execute() throws BuildException {
185 // check params --
186 // must have value or file
187 if ( value == null && file == null )
188 throw new BuildException( "Must have property, value, or file." );
189 // if no file, must have outputDir
190 if ( file == null && outputDir == null )
191 throw new BuildException( "Must have output directory." );
192 // must have only one of value or file
193 if ( value != null && file != null )
194 throw new BuildException( "Must not have more than one of property, value, or file." );
195
196 try {
197 if ( value != null )
198 splitValue();
199 else
200 splitFile();
201 }
202 catch ( Exception e ) {
203 if ( failOnError )
204 throw new BuildException( e.getMessage() );
205 else
206 log( e.getMessage() );
207 }
208 }
209
210 /**
211 * Split a string value into several files. Since the length of a String
212 * can be no more than Integer.MAX_VALUE, no special handling of the split
213 * sizes is required.
214 *
215 * @exception IOException if there is an i/o problem
216 */
217 private void splitValue() throws Exception {
218 if ( !outputDir.exists() && !outputDir.mkdirs() ) {
219 throw new IOException( "Unable to create output directory." );
220 }
221
222 StringReader reader = new StringReader( value );
223 int bytes_read = 0;
224 int suffix = 0;
225 if ( bytes > 0 ) {
226 // make files all the same number of bytes
227 char[] buffer = new char[ bytes ];
228 while ( bytes_read > -1 ) {
229 bytes_read = reader.read( buffer, 0, bytes );
230 if ( bytes_read == -1 )
231 break;
232 FileWriter fw = new FileWriter( new File( outputDir, prefix + "." + String.valueOf( suffix ) ) );
233 fw.write( buffer, 0, bytes_read );
234 fw.flush();
235 fw.close();
236 ++suffix;
237 }
238 }
239 else {
240 // make files all the same number of lines
241 splitByLines( reader );
242 }
243 }
244
245 /**
246 * Split a file into several files. Need some special handling here since
247 * a file could be larger than Integer.MAX_VALUE, in fact, a file can be at
248 * most Long.MAX_VALUE.
249 *
250 * @exception IOException if there is an i/o problem
251 */
252 private void splitFile() throws IOException {
253 if ( !file.exists() )
254 throw new FileNotFoundException( file.toString() );
255 if ( file.length() == 0 )
256 throw new BuildException( "Zero length file." );
257 if ( outputDir == null )
258 outputDir = file.getParentFile();
259 if ( !outputDir.exists() && !outputDir.mkdirs() ) {
260 throw new IOException( "Unable to create output directory." );
261 }
262
263 if ( bytes > 0 ) {
264 int suffix = 0;
265 int num_parts = ( int ) ( file.length() / ( long ) bytes );
266 int last_part_size = ( int ) ( file.length() % ( long ) bytes );
267 boolean one_more = last_part_size > 0;
268 BufferedInputStream bis = new BufferedInputStream( new FileInputStream( file ) );
269 for ( int i = 0; i < num_parts; i++ ) {
270 // make files all the same number of bytes
271 FileOutputStream fos = new FileOutputStream( new File( outputDir, prefix + "." + String.valueOf( suffix ) ) );
272 copyToStream( bis, fos, bytes );
273 fos.flush();
274 fos.close();
275 ++suffix;
276 }
277 if ( one_more ) {
278 FileOutputStream fos = new FileOutputStream( new File( outputDir, prefix + "." + String.valueOf( suffix ) ) );
279 copyToStream( bis, fos, last_part_size );
280 fos.flush();
281 fos.close();
282 }
283 bis.close();
284 }
285 else {
286 // make files all the same number of lines
287 splitByLines( new FileReader( file ) );
288 }
289 }
290
291 private void splitByLines( Reader reader ) throws IOException {
292 int suffix = 0;
293 LineNumberReader lnr = new LineNumberReader( reader );
294 String line = lnr.readLine();
295 BufferedWriter writer = new BufferedWriter( new FileWriter( new File( outputDir, prefix + "." + String.valueOf( suffix ) ) ) );
296 while ( line != null ) {
297 writer.write( line );
298 writer.newLine();
299 if ( lnr.getLineNumber() % lines == 0 ) {
300 writer.flush();
301 writer.close();
302 ++suffix;
303 writer = new BufferedWriter( new FileWriter( new File( outputDir, prefix + "." + String.valueOf( suffix ) ) ) );
304 }
305 line = lnr.readLine();
306 }
307 writer.flush();
308 writer.close();
309 }
310
311 private int calcSize(String b) throws NumberFormatException {
312 if ( b == null || b.length() == 0 )
313 return 0;
314 b = b.toLowerCase();
315 String modifier = b.substring( b.length() - 1 );
316 int multiplier = 1;
317 b = b.substring( 0, b.length() - 1 );
318 if ( modifier.equals( "b" ) ) {
319 multiplier = 512;
320 }
321 else if ( modifier.equals( "k" ) ) {
322 multiplier = 1024;
323 }
324 else if ( modifier.equals( "m" ) ) {
325 multiplier = 1024 * 1024;
326 }
327 else {
328 // modifier is not recognized, so put it back, maybe it's a number
329 b = b + modifier;
330 }
331 int size = Integer.parseInt( b ) * multiplier;
332 if (size <= 0) {
333 throw new NumberFormatException();
334 }
335 return size;
336 }
337
338
339 /**
340 * Copies a stream to another stream.
341 *
342 * @param from stream to copy from
343 * @param to file to write
344 * @param size number of bytes to copy from 'from' to 'to'
345 * @return actual number of bytes copied from 'from' to 'to'
346 * @exception IOException on any file error
347 */
348 private int copyToStream( InputStream from, OutputStream to, int size ) throws IOException {
349 int buffer_size = BUFFER_SIZE;
350 if ( size <= BUFFER_SIZE ) {
351 buffer_size = size;
352 }
353 byte[] buffer = new byte[ Math.min( BUFFER_SIZE, size ) ];
354 int bytes_read;
355 int total = 0;
356 int offset = 0;
357 while ( total < size ) {
358 bytes_read = from.read( buffer, 0, Math.min( buffer_size, size - offset ) );
359 if ( bytes_read == -1 )
360 break;
361 to.write( buffer, 0, bytes_read );
362 total += bytes_read;
363 offset += bytes_read;
364 }
365 to.flush();
366 return total;
367 }
368}
Note: See TracBrowser for help on using the repository browser.