Source Code Cross Referenced for DbaseFileHeader.java in  » GIS » GeoTools-2.4.1 » org » geotools » data » shapefile » dbf » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.data.shapefile.dbf 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2002-2006, Geotools Project Managment Committee (PMC)
005:         *    (C) 2002, Centre for Computational Geography
006:         *
007:         *    This library is free software; you can redistribute it and/or
008:         *    modify it under the terms of the GNU Lesser General Public
009:         *    License as published by the Free Software Foundation; either
010:         *    version 2.1 of the License, or (at your option) any later version.
011:         *
012:         *    This library is distributed in the hope that it will be useful,
013:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         *    Lesser General Public License for more details.
016:         *
017:         *    This file is based on an origional contained in the GISToolkit project:
018:         *    http://gistoolkit.sourceforge.net/
019:         */
020:        package org.geotools.data.shapefile.dbf;
021:
022:        import java.io.EOFException;
023:        import java.io.IOException;
024:        import java.nio.ByteBuffer;
025:        import java.nio.ByteOrder;
026:        import java.nio.channels.ReadableByteChannel;
027:        import java.nio.channels.WritableByteChannel;
028:        import java.util.ArrayList;
029:        import java.util.Calendar;
030:        import java.util.Date;
031:        import java.util.List;
032:        import java.util.logging.Level;
033:        import java.util.logging.Logger;
034:
035:        import org.geotools.resources.NIOUtilities;
036:
037:        /** Class to represent the header of a Dbase III file.
038:         * Creation date: (5/15/2001 5:15:30 PM)
039:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/plugin/shapefile/src/main/java/org/geotools/data/shapefile/dbf/DbaseFileHeader.java $
040:         */
041:        public class DbaseFileHeader {
042:            // Constant for the size of a record
043:            private static final int FILE_DESCRIPTOR_SIZE = 32;
044:
045:            // type of the file, must be 03h
046:            private static final byte MAGIC = 0x03;
047:
048:            private static final int MINIMUM_HEADER = 33;
049:
050:            // Date the file was last updated.
051:            private Date date = new Date();
052:
053:            private int recordCnt = 0;
054:
055:            private int fieldCnt = 0;
056:
057:            // set this to a default length of 1, which is enough for one "space"
058:            // character which signifies an empty record
059:            private int recordLength = 1;
060:
061:            // set this to a flagged value so if no fields are added before the write,
062:            // we know to adjust the headerLength to MINIMUM_HEADER
063:            private int headerLength = -1;
064:
065:            private int largestFieldSize = 0;
066:
067:            private Logger logger = org.geotools.util.logging.Logging
068:                    .getLogger("org.geotools.data.shapefile");
069:
070:            /**
071:             * Class for holding the information assicated with a record.
072:             */
073:            class DbaseField {
074:
075:                // Field Name
076:                String fieldName;
077:
078:                // Field Type (C N L D or M)
079:                char fieldType;
080:
081:                // Field Data Address offset from the start of the record.
082:                int fieldDataAddress;
083:
084:                // Length of the data in bytes
085:                int fieldLength;
086:
087:                // Field decimal count in Binary, indicating where the decimal is
088:                int decimalCount;
089:
090:            }
091:
092:            // collection of header records.
093:            // lets start out with a zero-length array, just in case
094:            private DbaseField[] fields = new DbaseField[0];
095:
096:            private void read(ByteBuffer buffer, ReadableByteChannel channel)
097:                    throws IOException {
098:                while (buffer.remaining() > 0) {
099:                    if (channel.read(buffer) == -1) {
100:                        throw new EOFException("Premature end of file");
101:                    }
102:                }
103:            }
104:
105:            /** Determine the most appropriate Java Class for representing the data in the
106:             * field.
107:             * <PRE>
108:             * All packages are java.lang unless otherwise specified.
109:             * C (Character) -> String
110:             * N (Numeric)   -> Integer or Double (depends on field's decimal count)
111:             * F (Floating)  -> Double
112:             * L (Logical)   -> Boolean
113:             * D (Date)      -> java.util.Date
114:             * Unknown       -> String
115:             * </PRE>
116:             * @param i The index of the field, from 0 to <CODE>getNumFields() - 1</CODE> .
117:             * @return A Class which closely represents the dbase field type.
118:             */
119:            public Class getFieldClass(int i) {
120:                Class typeClass = null;
121:
122:                switch (fields[i].fieldType) {
123:                case 'C':
124:                    typeClass = String.class;
125:                    break;
126:
127:                case 'N':
128:                    if (fields[i].decimalCount == 0) {
129:                        if (fields[i].fieldLength < 10) {
130:                            typeClass = Integer.class;
131:                        } else {
132:                            typeClass = Long.class;
133:                        }
134:                    } else {
135:                        typeClass = Double.class;
136:                    }
137:                    break;
138:
139:                case 'F':
140:                    typeClass = Double.class;
141:                    break;
142:
143:                case 'L':
144:                    typeClass = Boolean.class;
145:                    break;
146:
147:                case 'D':
148:                    typeClass = Date.class;
149:                    break;
150:
151:                default:
152:                    typeClass = String.class;
153:                    break;
154:                }
155:
156:                return typeClass;
157:            }
158:
159:            /** Add a column to this DbaseFileHeader.
160:             * The type is one of (C N L or D) character, number, logical(true/false), or date.
161:             * The Field length is the total length in bytes reserved for this column.
162:             * The decimal count only applies to numbers(N), and floating point values (F),
163:             * and refers to the number of characters to reserve after the decimal point.
164:             * <B>Don't expect miracles from this...</B>
165:             * <PRE>
166:             * Field Type MaxLength
167:             * ---------- ---------
168:             * C          254
169:             * D          8
170:             * F          20
171:             * N          18
172:             * </PRE>
173:             * @param inFieldName The name of the new field, must be less than 10 characters or it
174:             * gets truncated.
175:             * @param inFieldType A character representing the dBase field, ( see above ).
176:             * Case insensitive.
177:             * @param inFieldLength The length of the field, in bytes ( see above )
178:             * @param inDecimalCount For numeric fields, the number of decimal places to track.
179:             * @throws DbaseFileException If the type is not recognized.
180:             */
181:            public void addColumn(String inFieldName, char inFieldType,
182:                    int inFieldLength, int inDecimalCount)
183:                    throws DbaseFileException {
184:                if (inFieldLength <= 0) {
185:                    throw new DbaseFileException("field length <= 0");
186:                }
187:                if (fields == null) {
188:                    fields = new DbaseField[0];
189:                }
190:                int tempLength = 1; // the length is used for the offset, and there is a * for deleted as the first byte
191:                DbaseField[] tempFieldDescriptors = new DbaseField[fields.length + 1];
192:                for (int i = 0; i < fields.length; i++) {
193:                    fields[i].fieldDataAddress = tempLength;
194:                    tempLength = tempLength + fields[i].fieldLength;
195:                    tempFieldDescriptors[i] = fields[i];
196:                }
197:                tempFieldDescriptors[fields.length] = new DbaseField();
198:                tempFieldDescriptors[fields.length].fieldLength = inFieldLength;
199:                tempFieldDescriptors[fields.length].decimalCount = inDecimalCount;
200:                tempFieldDescriptors[fields.length].fieldDataAddress = tempLength;
201:
202:                // set the field name
203:                String tempFieldName = inFieldName;
204:                if (tempFieldName == null) {
205:                    tempFieldName = "NoName";
206:                }
207:                // Fix for GEOT-42, ArcExplorer will not handle field names > 10 chars
208:                // Sorry folks.
209:                if (tempFieldName.length() > 10) {
210:                    tempFieldName = tempFieldName.substring(0, 10);
211:                    if (logger.isLoggable(Level.WARNING)) {
212:                        logger
213:                                .warning("FieldName "
214:                                        + inFieldName
215:                                        + " is longer than 10 characters, truncating to "
216:                                        + tempFieldName);
217:                    }
218:                }
219:                tempFieldDescriptors[fields.length].fieldName = tempFieldName;
220:
221:                // the field type
222:                if ((inFieldType == 'C') || (inFieldType == 'c')) {
223:                    tempFieldDescriptors[fields.length].fieldType = 'C';
224:                    if (inFieldLength > 254) {
225:                        if (logger.isLoggable(Level.FINE)) {
226:                            logger
227:                                    .fine("Field Length for "
228:                                            + inFieldName
229:                                            + " set to "
230:                                            + inFieldLength
231:                                            + " Which is longer than 254, not consistent with dbase III");
232:                        }
233:                    }
234:                } else if ((inFieldType == 'S') || (inFieldType == 's')) {
235:                    tempFieldDescriptors[fields.length].fieldType = 'C';
236:                    if (logger.isLoggable(Level.WARNING)) {
237:                        logger
238:                                .warning("Field type for "
239:                                        + inFieldName
240:                                        + " set to S which is flat out wrong people!, I am setting this to C, in the hopes you meant character.");
241:                    }
242:                    if (inFieldLength > 254) {
243:                        if (logger.isLoggable(Level.FINE)) {
244:                            logger
245:                                    .fine("Field Length for "
246:                                            + inFieldName
247:                                            + " set to "
248:                                            + inFieldLength
249:                                            + " Which is longer than 254, not consistent with dbase III");
250:                        }
251:                    }
252:                    tempFieldDescriptors[fields.length].fieldLength = 8;
253:                } else if ((inFieldType == 'D') || (inFieldType == 'd')) {
254:                    tempFieldDescriptors[fields.length].fieldType = 'D';
255:                    if (inFieldLength != 8) {
256:                        if (logger.isLoggable(Level.FINE)) {
257:                            logger.fine("Field Length for " + inFieldName
258:                                    + " set to " + inFieldLength
259:                                    + " Setting to 8 digets YYYYMMDD");
260:                        }
261:                    }
262:                    tempFieldDescriptors[fields.length].fieldLength = 8;
263:                } else if ((inFieldType == 'F') || (inFieldType == 'f')) {
264:                    tempFieldDescriptors[fields.length].fieldType = 'F';
265:                    if (inFieldLength > 20) {
266:                        if (logger.isLoggable(Level.FINE)) {
267:                            logger
268:                                    .fine("Field Length for "
269:                                            + inFieldName
270:                                            + " set to "
271:                                            + inFieldLength
272:                                            + " Preserving length, but should be set to Max of 20 not valid for dbase IV, and UP specification, not present in dbaseIII.");
273:                        }
274:                    }
275:                } else if ((inFieldType == 'N') || (inFieldType == 'n')) {
276:                    tempFieldDescriptors[fields.length].fieldType = 'N';
277:                    if (inFieldLength > 18) {
278:                        if (logger.isLoggable(Level.FINE)) {
279:                            logger
280:                                    .fine("Field Length for "
281:                                            + inFieldName
282:                                            + " set to "
283:                                            + inFieldLength
284:                                            + " Preserving length, but should be set to Max of 18 for dbase III specification.");
285:                        }
286:                    }
287:                    if (inDecimalCount < 0) {
288:                        if (logger.isLoggable(Level.FINE)) {
289:                            logger
290:                                    .fine("Field Decimal Position for "
291:                                            + inFieldName
292:                                            + " set to "
293:                                            + inDecimalCount
294:                                            + " Setting to 0 no decimal data will be saved.");
295:                        }
296:                        tempFieldDescriptors[fields.length].decimalCount = 0;
297:                    }
298:                    if (inDecimalCount > inFieldLength - 1) {
299:                        if (logger.isLoggable(Level.WARNING)) {
300:                            logger.warning("Field Decimal Position for "
301:                                    + inFieldName + " set to " + inDecimalCount
302:                                    + " Setting to " + (inFieldLength - 1)
303:                                    + " no non decimal data will be saved.");
304:                        }
305:                        tempFieldDescriptors[fields.length].decimalCount = inFieldLength - 1;
306:                    }
307:                } else if ((inFieldType == 'L') || (inFieldType == 'l')) {
308:                    tempFieldDescriptors[fields.length].fieldType = 'L';
309:                    if (inFieldLength != 1) {
310:                        if (logger.isLoggable(Level.FINE)) {
311:                            logger
312:                                    .fine("Field Length for "
313:                                            + inFieldName
314:                                            + " set to "
315:                                            + inFieldLength
316:                                            + " Setting to length of 1 for logical fields.");
317:                        }
318:                    }
319:                    tempFieldDescriptors[fields.length].fieldLength = 1;
320:                } else {
321:                    throw new DbaseFileException("Undefined field type "
322:                            + inFieldType + " For column " + inFieldName);
323:                }
324:                // the length of a record
325:                tempLength = tempLength
326:                        + tempFieldDescriptors[fields.length].fieldLength;
327:
328:                // set the new fields.
329:                fields = tempFieldDescriptors;
330:                fieldCnt = fields.length;
331:                headerLength = MINIMUM_HEADER + 32 * fields.length;
332:                recordLength = tempLength;
333:            }
334:
335:            /** Remove a column from this DbaseFileHeader.
336:             * @todo This is really ugly, don't know who wrote it, but it needs fixin...
337:             * @param inFieldName The name of the field, will ignore case and trim.
338:             * @return index of the removed column, -1 if no found
339:             */
340:            public int removeColumn(String inFieldName) {
341:
342:                int retCol = -1;
343:                int tempLength = 1;
344:                DbaseField[] tempFieldDescriptors = new DbaseField[fields.length - 1];
345:                for (int i = 0, j = 0; i < fields.length; i++) {
346:                    if (!inFieldName.equalsIgnoreCase(fields[i].fieldName
347:                            .trim())) {
348:                        // if this is the last field and we still haven't found the
349:                        // named field
350:                        if (i == j && i == fields.length - 1) {
351:                            System.err.println("Could not find a field named '"
352:                                    + inFieldName + "' for removal");
353:                            return retCol;
354:                        }
355:                        tempFieldDescriptors[j] = fields[i];
356:                        tempFieldDescriptors[j].fieldDataAddress = tempLength;
357:                        tempLength += tempFieldDescriptors[j].fieldLength;
358:                        // only increment j on non-matching fields
359:                        j++;
360:                    } else {
361:                        retCol = i;
362:                    }
363:                }
364:
365:                // set the new fields.
366:                fields = tempFieldDescriptors;
367:                headerLength = 33 + 32 * fields.length;
368:                recordLength = tempLength;
369:
370:                return retCol;
371:            }
372:
373:            // Retrieve the length of the field at the given index
374:            /** Returns the field length in bytes.
375:             * @param inIndex The field index.
376:             * @return The length in bytes.
377:             */
378:            public int getFieldLength(int inIndex) {
379:                return fields[inIndex].fieldLength;
380:            }
381:
382:            // Retrieve the location of the decimal point within the field.
383:            /** Get the decimal count of this field.
384:             * @param inIndex The field index.
385:             * @return The decimal count.
386:             */
387:            public int getFieldDecimalCount(int inIndex) {
388:                return fields[inIndex].decimalCount;
389:            }
390:
391:            // Retrieve the Name of the field at the given index
392:            /** Get the field name.
393:             * @param inIndex The field index.
394:             * @return The name of the field.
395:             */
396:            public String getFieldName(int inIndex) {
397:                return fields[inIndex].fieldName;
398:            }
399:
400:            // Retrieve the type of field at the given index
401:            /** Get the character class of the field.
402:             * @param inIndex The field index.
403:             * @return The dbase character representing this field.
404:             */
405:            public char getFieldType(int inIndex) {
406:                return fields[inIndex].fieldType;
407:            }
408:
409:            /** Get the date this file was last updated.
410:             * @return The Date last modified.
411:             */
412:            public Date getLastUpdateDate() {
413:                return date;
414:            }
415:
416:            /** Return the number of fields in the records.
417:             * @return The number of fields in this table.
418:             */
419:            public int getNumFields() {
420:                return fields.length;
421:            }
422:
423:            /** Return the number of records in the file
424:             * @return The number of records in this table.
425:             */
426:            public int getNumRecords() {
427:                return recordCnt;
428:            }
429:
430:            /** Get the length of the records in bytes.
431:             * @return The number of bytes per record.
432:             */
433:            public int getRecordLength() {
434:                return recordLength;
435:            }
436:
437:            /** Get the length of the header
438:             * @return The length of the header in bytes.
439:             */
440:            public int getHeaderLength() {
441:                return headerLength;
442:            }
443:
444:            /** Read the header data from the DBF file.
445:             * @param channel A readable byte channel. If you have an InputStream you need to use, you can
446:             * call java.nio.Channels.getChannel(InputStream in).
447:             * @throws IOException If errors occur while reading.
448:             */
449:            public void readHeader(ReadableByteChannel channel)
450:                    throws IOException {
451:                // we'll read in chunks of 1K
452:                ByteBuffer in = ByteBuffer.allocateDirect(1024);
453:                // do this or GO CRAZY
454:                // ByteBuffers come preset to BIG_ENDIAN !
455:                in.order(ByteOrder.LITTLE_ENDIAN);
456:
457:                // only want to read first 10 bytes...
458:                in.limit(10);
459:
460:                read(in, channel);
461:                in.position(0);
462:
463:                // type of file.
464:                byte magic = in.get();
465:                if (magic != MAGIC) {
466:                    throw new IOException("Unsupported DBF file Type "
467:                            + Integer.toHexString(magic));
468:                }
469:
470:                // parse the update date information.
471:                int tempUpdateYear = in.get();
472:                int tempUpdateMonth = in.get();
473:                int tempUpdateDay = in.get();
474:                // ouch Y2K uncompliant
475:                if (tempUpdateYear > 90) {
476:                    tempUpdateYear = tempUpdateYear + 1900;
477:                } else {
478:                    tempUpdateYear = tempUpdateYear + 2000;
479:                }
480:                Calendar c = Calendar.getInstance();
481:                c.set(Calendar.YEAR, tempUpdateYear);
482:                c.set(Calendar.MONTH, tempUpdateMonth - 1);
483:                c.set(Calendar.DATE, tempUpdateDay);
484:                date = c.getTime();
485:
486:                // read the number of records.
487:                recordCnt = in.getInt();
488:
489:                // read the length of the header structure.
490:                // ahhh.. unsigned little-endian shorts
491:                // mask out the byte and or it with shifted 2nd byte
492:                headerLength = (in.get() & 0xff) | ((in.get() & 0xff) << 8);
493:
494:                // if the header is bigger than our 1K, reallocate
495:                if (headerLength > in.capacity()) {
496:                    NIOUtilities.clean(in);
497:                    in = ByteBuffer.allocateDirect(headerLength - 10);
498:                }
499:                in.limit(headerLength - 10);
500:                in.position(0);
501:                read(in, channel);
502:                in.position(0);
503:
504:                // read the length of a record
505:                // ahhh.. unsigned little-endian shorts
506:                recordLength = (in.get() & 0xff) | ((in.get() & 0xff) << 8);
507:
508:                // skip / skip thesreserved bytes in the header.
509:                in.position(in.position() + 20);
510:
511:                // calculate the number of Fields in the header
512:                fieldCnt = (headerLength - FILE_DESCRIPTOR_SIZE - 1)
513:                        / FILE_DESCRIPTOR_SIZE;
514:
515:                // read all of the header records
516:                List lfields = new ArrayList();
517:                for (int i = 0; i < fieldCnt; i++) {
518:                    DbaseField field = new DbaseField();
519:
520:                    // read the field name
521:                    byte[] buffer = new byte[11];
522:                    in.get(buffer);
523:                    String name = new String(buffer);
524:                    int nullPoint = name.indexOf(0);
525:                    if (nullPoint != -1) {
526:                        name = name.substring(0, nullPoint);
527:                    }
528:                    field.fieldName = name.trim();
529:
530:                    // read the field type
531:                    field.fieldType = (char) in.get();
532:
533:                    // read the field data address, offset from the start of the record.
534:                    field.fieldDataAddress = in.getInt();
535:
536:                    // read the field length in bytes
537:                    int length = (int) in.get();
538:                    if (length < 0) {
539:                        length = length + 256;
540:                    }
541:                    field.fieldLength = length;
542:
543:                    if (length > largestFieldSize) {
544:                        largestFieldSize = length;
545:                    }
546:
547:                    // read the field decimal count in bytes
548:                    field.decimalCount = (int) in.get();
549:
550:                    // rreservedvededved bytes.
551:                    //in.skipBytes(14);
552:                    in.position(in.position() + 14);
553:
554:                    // some broken shapefiles have 0-length attributes. The reference implementation
555:                    // (ArcExplorer 2.0, built with MapObjects) just ignores them.
556:                    if (field.fieldLength > 0) {
557:                        lfields.add(field);
558:                    }
559:                }
560:
561:                // Last byte is a marker for the end of the field definitions.
562:                //in.skipBytes(1);
563:                in.position(in.position() + 1);
564:
565:                NIOUtilities.clean(in);
566:
567:                fields = new DbaseField[lfields.size()];
568:                fields = (DbaseField[]) lfields.toArray(fields);
569:            }
570:
571:            /** Get the largest field size of this table.
572:             * @return The largt field size iiin bytes.
573:             */
574:            public int getLargestFieldSize() {
575:                return largestFieldSize;
576:            }
577:
578:            /** Set the number of records in the file
579:             * @param inNumRecords The number of records.
580:             */
581:            public void setNumRecords(int inNumRecords) {
582:                recordCnt = inNumRecords;
583:            }
584:
585:            /** Write the header data to the DBF file.
586:             * @param out A channel to write to. If you have an OutputStream you can obtain the correct
587:             * channel by using java.nio.Channels.newChannel(OutputStream out).
588:             * @throws IOException If errors occur.
589:             */
590:            public void writeHeader(WritableByteChannel out) throws IOException {
591:                // take care of the annoying case where no records have been added...
592:                if (headerLength == -1) {
593:                    headerLength = MINIMUM_HEADER;
594:                }
595:                ByteBuffer buffer = ByteBuffer.allocateDirect(headerLength);
596:                buffer.order(ByteOrder.LITTLE_ENDIAN);
597:
598:                // write the output file type.
599:                buffer.put((byte) MAGIC);
600:
601:                // write the date stuff
602:                Calendar c = Calendar.getInstance();
603:                c.setTime(new Date());
604:                buffer.put((byte) (c.get(Calendar.YEAR) % 100));
605:                buffer.put((byte) (c.get(Calendar.MONTH) + 1));
606:                buffer.put((byte) (c.get(Calendar.DAY_OF_MONTH)));
607:
608:                // write the number of records in the datafile.
609:                buffer.putInt(recordCnt);
610:
611:                // write the length of the header structure.
612:                buffer.putShort((short) headerLength);
613:
614:                // write the length of a record
615:                buffer.putShort((short) recordLength);
616:
617:                //    // write the reserved bytes in the header
618:                //    for (int i=0; i<20; i++) out.writeByteLE(0);
619:                buffer.position(buffer.position() + 20);
620:
621:                // write all of the header records
622:                int tempOffset = 0;
623:                for (int i = 0; i < fields.length; i++) {
624:
625:                    // write the field name
626:                    for (int j = 0; j < 11; j++) {
627:                        if (fields[i].fieldName.length() > j) {
628:                            buffer.put((byte) fields[i].fieldName.charAt(j));
629:                        } else {
630:                            buffer.put((byte) 0);
631:                        }
632:                    }
633:
634:                    // write the field type
635:                    buffer.put((byte) fields[i].fieldType);
636:                    //    // write the field data address, offset from the start of the record.
637:                    buffer.putInt(tempOffset);
638:                    tempOffset += fields[i].fieldLength;
639:
640:                    // write the length of the field.
641:                    buffer.put((byte) fields[i].fieldLength);
642:
643:                    // write the decimal count.
644:                    buffer.put((byte) fields[i].decimalCount);
645:
646:                    // write the reserved bytes.
647:                    //for (in j=0; jj<14; j++) out.writeByteLE(0);
648:                    buffer.position(buffer.position() + 14);
649:                }
650:
651:                // write the end of the field definitions marker
652:                buffer.put((byte) 0x0D);
653:
654:                buffer.position(0);
655:
656:                int r = buffer.remaining();
657:                while ((r -= out.write(buffer)) > 0) {
658:                    ; // do nothing
659:                }
660:
661:                NIOUtilities.clean(buffer);
662:            }
663:
664:            /** Get a simple representation of this header.
665:             * @return A String representing the state of the header.
666:             */
667:            public String toString() {
668:                StringBuffer fs = new StringBuffer();
669:                for (int i = 0, ii = fields.length; i < ii; i++) {
670:                    DbaseField f = fields[i];
671:                    fs.append(f.fieldName + " " + f.fieldType + " "
672:                            + f.fieldLength + " " + f.decimalCount + " "
673:                            + f.fieldDataAddress + "\n");
674:                }
675:
676:                return "DB3 Header\n" + "Date : " + date + "\n" + "Records : "
677:                        + recordCnt + "\n" + "Fields : " + fieldCnt + "\n" + fs;
678:
679:            }
680:
681:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.