Statistics
| Revision:

root / branches / piloto3d / libraries / libFMap / src / com / iver / cit / gvsig / fmap / drivers / dbf / DbaseFile.java @ 9524

History | View | Annotate | Download (11.3 KB)

1
/*
2
 * Created on 16-feb-2004
3
 *
4
 * To change the template for this generated file go to
5
 * Window>Preferences>Java>Code Generation>Code and Comments
6
 */
7
package com.iver.cit.gvsig.fmap.drivers.dbf;
8

    
9
/**
10
 */
11
import java.io.File;
12
import java.io.FileNotFoundException;
13
import java.io.IOException;
14
import java.io.RandomAccessFile;
15
import java.io.UnsupportedEncodingException;
16
import java.nio.ByteBuffer;
17
import java.nio.channels.FileChannel;
18
import java.nio.charset.Charset;
19
import java.text.FieldPosition;
20
import java.text.NumberFormat;
21
import java.util.Calendar;
22
import java.util.Date;
23
import java.util.Locale;
24

    
25
import com.iver.utiles.bigfile.BigByteBuffer2;
26

    
27
/**
28
 * Class to read and write data to a dbase III format file. Creation date:
29
 * (5/15/2001 5:15:13 PM)
30
 */
31
public class DbaseFile {
32
        // Header information for the DBase File
33
        private DbaseFileHeader myHeader;
34

    
35
        private RandomAccessFile raf;
36

    
37
        private FileChannel channel;
38

    
39
        private BigByteBuffer2 buffer;
40

    
41
        private FileChannel.MapMode mode;
42

    
43
        private FieldFormatter formatter = new FieldFormatter();
44

    
45
        private int posActual = -1;
46

    
47
        private int recordOffset;
48

    
49
        private ByteBuffer cachedRecord = null;
50

    
51
        private byte[] bytesCachedRecord = null;
52

    
53
        private final Number NULL_NUMBER = new Integer(0);
54

    
55
        private final String NULL_STRING = "";
56

    
57
        private final String NULL_DATE = "        ";
58

    
59
        private Charset chars;
60

    
61
        /** Utility for formatting Dbase fields. */
62
        public static class FieldFormatter {
63
                private StringBuffer buffer = new StringBuffer(255);
64

    
65
                private NumberFormat numFormat = NumberFormat
66
                                .getNumberInstance(Locale.US);
67

    
68
                private Calendar calendar = Calendar.getInstance(Locale.US);
69

    
70
                private String emtpyString;
71

    
72
                private static final int MAXCHARS = 255;
73

    
74
                public FieldFormatter() {
75
                        // Avoid grouping on number format
76
                        numFormat.setGroupingUsed(false);
77

    
78
                        // build a 255 white spaces string
79
                        StringBuffer sb = new StringBuffer(MAXCHARS);
80
                        sb.setLength(MAXCHARS);
81
                        for (int i = 0; i < MAXCHARS; i++) {
82
                                sb.setCharAt(i, ' ');
83
                        }
84

    
85
                        emtpyString = sb.toString();
86
                }
87

    
88
                public String getFieldString(int size, String s) {
89
                        buffer.replace(0, size, emtpyString);
90
                        buffer.setLength(size);
91

    
92
                        if (s != null) {
93
                                buffer.replace(0, size, s);
94
                                if (s.length() <= size) {
95
                                        for (int i = s.length(); i < size; i++) {
96
                                                buffer.append(' ');
97
                                        }
98
                                }
99
                        }
100

    
101
                        buffer.setLength(size);
102
                        return buffer.toString();
103
                }
104

    
105
                public String getFieldString(Date d) {
106

    
107
                        if (d != null) {
108
                                buffer.delete(0, buffer.length());
109

    
110
                                calendar.setTime(d);
111
                                int year = calendar.get(Calendar.YEAR);
112
                                int month = calendar.get(Calendar.MONTH) + 1; // returns 0
113
                                                                                                                                // based month?
114
                                int day = calendar.get(Calendar.DAY_OF_MONTH);
115

    
116
                                if (year < 1000) {
117
                                        if (year >= 100) {
118
                                                buffer.append("0");
119
                                        } else if (year >= 10) {
120
                                                buffer.append("00");
121
                                        } else {
122
                                                buffer.append("000");
123
                                        }
124
                                }
125
                                buffer.append(year);
126

    
127
                                if (month < 10) {
128
                                        buffer.append("0");
129
                                }
130
                                buffer.append(month);
131

    
132
                                if (day < 10) {
133
                                        buffer.append("0");
134
                                }
135
                                buffer.append(day);
136
                        } else {
137
                                buffer.setLength(8);
138
                                buffer.replace(0, 8, emtpyString);
139
                        }
140

    
141
                        buffer.setLength(8);
142
                        return buffer.toString();
143
                }
144

    
145
                public String getFieldString(int size, int decimalPlaces, Number n) {
146
                        buffer.delete(0, buffer.length());
147

    
148
                        if (n != null) {
149
                                numFormat.setMaximumFractionDigits(decimalPlaces);
150
                                numFormat.setMinimumFractionDigits(decimalPlaces);
151
                                numFormat.format(n, buffer, new FieldPosition(
152
                                                NumberFormat.INTEGER_FIELD));
153
                        }
154

    
155
                        int diff = size - buffer.length();
156
                        if (diff >= 0) {
157
                                while (diff-- > 0) {
158
                                        buffer.insert(0, ' ');
159
                                }
160
                        } else {
161
                                buffer.setLength(size);
162
                        }
163
                        return buffer.toString();
164
                }
165
        }
166

    
167
        // Retrieve number of records in the DbaseFile
168
        public int getRecordCount() {
169
                return myHeader.getNumRecords();
170
        }
171

    
172
        /**
173
         * DOCUMENT ME!
174
         * 
175
         * @return DOCUMENT ME!
176
         */
177
        public int getFieldCount() {
178
                return myHeader.getNumFields();
179
        }
180

    
181
        /**
182
         * DOCUMENT ME!
183
         * 
184
         * @param rowIndex
185
         *            DOCUMENT ME!
186
         * @param fieldId
187
         *            DOCUMENT ME!
188
         * 
189
         * @return DOCUMENT ME!
190
         */
191
        public boolean getBooleanFieldValue(int rowIndex, int fieldId) {
192
                int recordOffset = (myHeader.getRecordLength() * rowIndex)
193
                                + myHeader.getHeaderLength() + 1;
194

    
195
                // Se calcula el offset del campo
196
                int fieldOffset = 0;
197

    
198
                for (int i = 0; i < (fieldId - 1); i++) {
199
                        fieldOffset += myHeader.getFieldLength(i);
200
                }
201

    
202
                buffer.position(recordOffset + fieldOffset);
203

    
204
                char bool = (char) buffer.get();
205

    
206
                return ((bool == 't') || (bool == 'T') || (bool == 'Y') || (bool == 'y'));
207
        }
208

    
209
        /**
210
         * DOCUMENT ME!
211
         * 
212
         * @param rowIndex
213
         *            DOCUMENT ME!
214
         * @param fieldId
215
         *            DOCUMENT ME!
216
         * 
217
         * @return DOCUMENT ME!
218
         * @throws UnsupportedEncodingException
219
         */
220
        public String getStringFieldValue(int rowIndex, int fieldId)
221
                        throws UnsupportedEncodingException {
222
                int fieldOffset = myHeader.getFieldDescription(fieldId).myFieldDataAddress;
223
                byte[] data = new byte[myHeader.getFieldLength(fieldId)];
224
                if (rowIndex != posActual) {
225
                        recordOffset = (myHeader.getRecordLength() * rowIndex)
226
                                        + myHeader.getHeaderLength() + 1;
227

    
228
                        /*
229
                         * System.err.println("getStringFieldValue: rowIndex = " +
230
                         * rowIndex); System.err.println("recordOffset = " + recordOffset + "
231
                         * fieldOffset=" + fieldOffset);
232
                         */
233
                        buffer.position(recordOffset);
234
                        buffer.get(bytesCachedRecord);
235
                        cachedRecord = ByteBuffer.wrap(bytesCachedRecord);
236
                        posActual = rowIndex;
237

    
238
                }
239
                cachedRecord.position(fieldOffset);
240
                cachedRecord.get(data);
241

    
242
                return new String(data, chars.name());
243

    
244
        }
245

    
246
        public void setFieldValue(int rowIndex, int fieldId, Object obj)
247
                        throws IOException {
248
                int fieldOffset = myHeader.getFieldDescription(fieldId).myFieldDataAddress;
249
                String str = fieldString(obj, fieldId);
250
                byte[] data = new byte[myHeader.getFieldLength(fieldId)];
251
                recordOffset = (myHeader.getRecordLength() * rowIndex)
252
                                + myHeader.getHeaderLength() + 1;
253

    
254
                ByteBuffer aux = ByteBuffer.wrap(data);
255
                aux.put(str.getBytes(chars.name()));
256
//                raf.seek(recordOffset + fieldOffset);
257
//                raf.writeBytes(str);
258
                aux.flip();
259
                int numBytesWritten = channel.write(aux, recordOffset + fieldOffset);
260
                channel.force(true);
261
                
262

    
263
        }
264

    
265

    
266
        /**
267
         * Retrieve the name of the given column.
268
         * 
269
         * @param inIndex
270
         *            DOCUMENT ME!
271
         * 
272
         * @return DOCUMENT ME!
273
         */
274
        public String getFieldName(int inIndex) {
275
                return myHeader.getFieldName(inIndex).trim();
276
        }
277

    
278
        /**
279
         * Retrieve the type of the given column.
280
         * 
281
         * @param inIndex
282
         *            DOCUMENT ME!
283
         * 
284
         * @return DOCUMENT ME!
285
         */
286
        public char getFieldType(int inIndex) {
287
                return myHeader.getFieldType(inIndex);
288
        }
289

    
290
        /**
291
         * Retrieve the length of the given column.
292
         * 
293
         * @param inIndex
294
         *            DOCUMENT ME!
295
         * 
296
         * @return DOCUMENT ME!
297
         */
298
        public int getFieldLength(int inIndex) {
299
                return myHeader.getFieldLength(inIndex);
300
        }
301

    
302
        /*
303
         * Retrieve the value of the given column as string.
304
         * 
305
         * @param idField DOCUMENT ME! @param idRecord DOCUMENT ME!
306
         * 
307
         * @return DOCUMENT ME!
308
         * 
309
         * public Object getFieldValue(int idField, long idRecord) throws
310
         * IOException { Object[] tmpReg = getRecord(idRecord); return
311
         * tmpReg[idField]; }
312
         */
313
        /*
314
         * DOCUMENT ME!
315
         * 
316
         * @param idField DOCUMENT ME! @param idRecord DOCUMENT ME!
317
         * 
318
         * @return DOCUMENT ME!
319
         * 
320
         * public double getFieldValueAsDouble(int idField, int idRecord) throws
321
         * IOException { Object[] tmpReg = getRecord(idRecord); return (double)
322
         * Double.parseDouble(tmpReg[idField].toString()); }
323
         */
324

    
325
        /**
326
         * Retrieve the location of the decimal point.
327
         * 
328
         * @param inIndex
329
         *            DOCUMENT ME!
330
         * 
331
         * @return DOCUMENT ME!
332
         */
333
        public int getFieldDecimalLength(int inIndex) {
334
                return myHeader.getFieldDecimalCount(inIndex);
335
        }
336

    
337
        /**
338
         * read the DBF file into memory.
339
         * 
340
         * @param file
341
         *            DOCUMENT ME!
342
         * 
343
         * @throws IOException
344
         *             DOCUMENT ME!
345
         */
346
        public void open(File file) throws IOException {
347
                /*
348
                 * 01h DOS USA code page 437 02h DOS Multilingual code page 850 03h
349
                 * Windows ANSI code page 1252 04h Standard Macintosh 64h EE MS-DOS code
350
                 * page 852 65h Nordic MS-DOS code page 865 66h Russian MS-DOS code page
351
                 * 866 67h Icelandic MS-DOS 68h Kamenicky (Czech) MS-DOS 69h Mazovia
352
                 * (Polish) MS-DOS 6Ah Greek MS-DOS (437G) 6Bh Turkish MS-DOS 96h
353
                 * Russian Macintosh 97h Eastern European Macintosh 98h Greek Macintosh
354
                 * C8h Windows EE code page 1250 C9h Russian Windows CAh Turkish Windows
355
                 * CBh Greek Windows
356
                 */
357
                if (file.canWrite()) {
358
                        try {
359
                                raf = new RandomAccessFile(file, "rw");
360
                                mode = FileChannel.MapMode.READ_WRITE;
361
                        } catch (FileNotFoundException e) {
362
                                raf = new RandomAccessFile(file, "r");
363
                                mode = FileChannel.MapMode.READ_ONLY;
364
                        }
365
                } else {
366
                        raf = new RandomAccessFile(file, "r");
367
                        mode = FileChannel.MapMode.READ_ONLY;
368
                }
369
                channel = raf.getChannel();
370

    
371
                // buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0,
372
                // channel.size());
373
                buffer = new BigByteBuffer2(channel, mode);
374

    
375
                // create the header to contain the header information.
376
                myHeader = new DbaseFileHeader();
377
                myHeader.readHeader(buffer);
378
                switch (myHeader.getLanguageID()) {
379
                case 0x01:
380
                        chars = Charset.forName("US-ASCII");
381
                        break;
382
                case 0x02:
383
                        chars = Charset.forName("ISO-8859-1");
384
                        break;
385
                case 0x03:
386
                        chars = Charset.forName("windows-1252");
387
                        break;
388
                case 0x04:
389
                        chars = Charset.forName("mac");
390
                        break;
391
                case 0x64:
392
                        chars = Charset.forName("ISO-8859-1");
393
                        break;
394
                case 0x65:
395
                        chars = Charset.forName("ISO-8859-1");
396
                        break;
397
                case 0x66:
398
                        chars = Charset.forName("ISO-8859-1");
399
                        break;
400
                case 0x67:
401
                        chars = Charset.forName("ISO-8859-1");
402
                        break;
403
                case 0x68:
404
                        chars = Charset.forName("greek");
405
                        break;
406
                case 0x69:
407
                        chars = Charset.forName("ISO-8859-1");
408
                        break;
409
                case 0x6A:
410
                        chars = Charset.forName("greek");
411
                        break;
412
                case 0x6B:
413
                        chars = Charset.forName("ISO-8859-1");
414
                        break;
415

    
416
                default:
417
                        chars = Charset.forName("ISO-8859-1");
418
                }
419
                bytesCachedRecord = new byte[myHeader.getRecordLength()];
420
        }
421

    
422
        /**
423
         * Removes all data from the dataset
424
         * 
425
         * @throws IOException
426
         *             DOCUMENT ME!
427
         */
428
        public void close() throws IOException {
429
                raf.close();
430
                channel.close();
431
                buffer = null;
432
        }
433

    
434
        public FileChannel getWriteChannel() {
435
                return channel;
436
        }
437

    
438
        private String fieldString(Object obj, final int col) {
439
                String o;
440
                final int fieldLen = myHeader.getFieldLength(col);
441
                switch (myHeader.getFieldType(col)) {
442
                case 'C':
443
                case 'c':
444
                        o = formatter.getFieldString(fieldLen, (obj == null) ? NULL_STRING
445
                                        : ((String) obj));
446
                        break;
447
                case 'L':
448
                case 'l':
449
                        o = (obj == null) ? "F"
450
                                        : ((Boolean) obj).booleanValue() == true ? "T" : "F";
451
                        break;
452
                case 'M':
453
                case 'G':
454
                        o = formatter.getFieldString(fieldLen, (obj == null) ? NULL_STRING
455
                                        : ((String) obj));
456
                        break;
457
                case 'N':
458
                case 'n':
459
                case 'F':
460
                case 'f':
461
                        Number number = null;
462
                        if (obj == null) {
463
                                number = NULL_NUMBER;
464
                        } else {
465
                                Number gVal = (Number) obj;
466
                                number = new Double(gVal.doubleValue());
467
                        }
468
                        o = formatter.getFieldString(fieldLen, myHeader
469
                                        .getFieldDecimalCount(col), number);
470
                        break;
471
                case 'D':
472
                case 'd':
473
                        if (obj == null)
474
                                o = NULL_DATE;
475
                        else
476
                                o = formatter.getFieldString(((Date) obj));
477
                        break;
478
                default:
479
                        throw new RuntimeException("Unknown type "
480
                                        + myHeader.getFieldType(col));
481
                }
482

    
483
                return o;
484
        }
485

    
486
}