Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libFMap_dalfile / src / org / gvsig / fmap / dal / store / dbf / utils / DbaseFile.java @ 25789

History | View | Annotate | Download (13 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 org.gvsig.fmap.dal.store.dbf.utils;
8

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

    
23
import org.gvsig.fmap.dal.exception.CloseException;
24
import org.gvsig.fmap.dal.exception.FileNotFoundException;
25
import org.gvsig.fmap.dal.exception.UnsupportedEncodingException;
26
import org.gvsig.fmap.dal.exception.UnsupportedVersionException;
27
import org.gvsig.fmap.dal.exception.WriteException;
28

    
29
import com.iver.utiles.bigfile.BigByteBuffer2;
30

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

    
39
        private File file;
40

    
41
        private RandomAccessFile raf;
42

    
43
        private FileChannel channel;
44

    
45
        private BigByteBuffer2 buffer;
46

    
47
        private FileChannel.MapMode mode;
48

    
49
        private FieldFormatter formatter = new FieldFormatter();
50

    
51
        private long posActual = -1;
52

    
53
        private int recordOffset;
54

    
55
        private ByteBuffer cachedRecord = null;
56

    
57
        private byte[] bytesCachedRecord = null;
58

    
59
        private final Number NULL_NUMBER = new Integer(0);
60

    
61
        private final String NULL_STRING = "";
62

    
63
        private final String NULL_DATE = "        ";
64

    
65
        private Charset chars;
66

    
67
        private boolean isOpen = false;
68

    
69

    
70
        /** Utility for formatting Dbase fields. */
71
        public static class FieldFormatter {
72
                private StringBuffer buffer = new StringBuffer(255);
73

    
74
                private NumberFormat numFormat = NumberFormat
75
                                .getNumberInstance(Locale.US);
76

    
77
                private Calendar calendar = Calendar.getInstance(Locale.US);
78

    
79
                private String emtpyString;
80

    
81
                private static final int MAXCHARS = 255;
82

    
83
                public FieldFormatter() {
84
                        // Avoid grouping on number format
85
                        numFormat.setGroupingUsed(false);
86

    
87
                        // build a 255 white spaces string
88
                        StringBuffer sb = new StringBuffer(MAXCHARS);
89
                        sb.setLength(MAXCHARS);
90
                        for (int i = 0; i < MAXCHARS; i++) {
91
                                sb.setCharAt(i, ' ');
92
                        }
93

    
94
                        emtpyString = sb.toString();
95
                }
96

    
97
                public String getFieldString(int size, String s) {
98
                        buffer.replace(0, size, emtpyString);
99
                        buffer.setLength(size);
100

    
101
                        if (s != null) {
102
                                buffer.replace(0, size, s);
103
                                if (s.length() <= size) {
104
                                        for (int i = s.length(); i < size; i++) {
105
                                                buffer.append(' ');
106
                                        }
107
                                }
108
                        }
109

    
110
                        buffer.setLength(size);
111
                        return buffer.toString();
112
                }
113

    
114
                public String getFieldString(Date d) {
115

    
116
                        if (d != null) {
117
                                buffer.delete(0, buffer.length());
118

    
119
                                calendar.setTime(d);
120
                                int year = calendar.get(Calendar.YEAR);
121
                                int month = calendar.get(Calendar.MONTH) + 1; // returns 0
122
                                                                                                                                // based month?
123
                                int day = calendar.get(Calendar.DAY_OF_MONTH);
124

    
125
                                if (year < 1000) {
126
                                        if (year >= 100) {
127
                                                buffer.append("0");
128
                                        } else if (year >= 10) {
129
                                                buffer.append("00");
130
                                        } else {
131
                                                buffer.append("000");
132
                                        }
133
                                }
134
                                buffer.append(year);
135

    
136
                                if (month < 10) {
137
                                        buffer.append("0");
138
                                }
139
                                buffer.append(month);
140

    
141
                                if (day < 10) {
142
                                        buffer.append("0");
143
                                }
144
                                buffer.append(day);
145
                        } else {
146
                                buffer.setLength(8);
147
                                buffer.replace(0, 8, emtpyString);
148
                        }
149

    
150
                        buffer.setLength(8);
151
                        return buffer.toString();
152
                }
153

    
154
                public String getFieldString(int size, int decimalPlaces, Number n) {
155
                        buffer.delete(0, buffer.length());
156

    
157
                        if (n != null) {
158
                                numFormat.setMaximumFractionDigits(decimalPlaces);
159
                                numFormat.setMinimumFractionDigits(decimalPlaces);
160
                                numFormat.format(n, buffer, new FieldPosition(
161
                                                NumberFormat.INTEGER_FIELD));
162
                        }
163

    
164
                        int diff = size - buffer.length();
165
                        if (diff >= 0) {
166
                                while (diff-- > 0) {
167
                                        buffer.insert(0, ' ');
168
                                }
169
                        } else {
170
                                buffer.setLength(size);
171
                        }
172
                        return buffer.toString();
173
                }
174
        }
175

    
176
        public DbaseFile(File afile){
177
                this.file= afile;
178
        }
179

    
180
        public byte getCodePage() {
181
                return myHeader.getLanguageID();
182
        }
183

    
184
        // Retrieve number of records in the DbaseFile
185
        public int getRecordCount() {
186
                return myHeader.getNumRecords();
187
        }
188

    
189
        /**
190
         * DOCUMENT ME!
191
         *
192
         * @return DOCUMENT ME!
193
         */
194
        public int getFieldCount() {
195
                return myHeader.getNumFields();
196
        }
197

    
198
        /**
199
         * DOCUMENT ME!
200
         *
201
         * @param rowIndex
202
         *            DOCUMENT ME!
203
         * @param fieldId
204
         *            DOCUMENT ME!
205
         *
206
         * @return DOCUMENT ME!
207
         */
208
        public boolean getBooleanFieldValue(int rowIndex, int fieldId) {
209
                int recordOffset = (myHeader.getRecordLength() * rowIndex)
210
                                + myHeader.getHeaderLength() + 1;
211

    
212
                // Se calcula el offset del campo
213
                int fieldOffset = 0;
214

    
215
                for (int i = 0; i < (fieldId - 1); i++) {
216
                        fieldOffset += myHeader.getFieldLength(i);
217
                }
218

    
219
                buffer.position(recordOffset + fieldOffset);
220

    
221
                char bool = (char) buffer.get();
222

    
223
                return ((bool == 't') || (bool == 'T') || (bool == 'Y') || (bool == 'y'));
224
        }
225

    
226
        /**
227
         * DOCUMENT ME!
228
         *
229
         * @param rowIndex
230
         *            DOCUMENT ME!
231
         * @param fieldId
232
         *            DOCUMENT ME!
233
         *
234
         * @return DOCUMENT ME!
235
         * @throws UnsupportedEncodingException
236
         */
237
        public String getStringFieldValue(int rowIndex, int fieldId)
238
                        throws UnsupportedEncodingException {
239
                int fieldOffset = myHeader.getFieldDescription(fieldId).myFieldDataAddress;
240
                byte[] data = new byte[myHeader.getFieldLength(fieldId)];
241
                if (rowIndex != posActual) {
242
                        recordOffset = (myHeader.getRecordLength() * rowIndex)
243
                                        + myHeader.getHeaderLength() + 1;
244

    
245
                        /*
246
                         * System.err.println("getStringFieldValue: rowIndex = " +
247
                         * rowIndex); System.err.println("recordOffset = " + recordOffset + "
248
                         * fieldOffset=" + fieldOffset);
249
                         */
250

    
251
                        buffer.position(recordOffset);
252
                        buffer.get(bytesCachedRecord);
253
                        cachedRecord = ByteBuffer.wrap(bytesCachedRecord);
254
                        posActual = rowIndex;
255

    
256
                }
257
                cachedRecord.position(fieldOffset);
258
                cachedRecord.get(data);
259

    
260
                try {
261
                        return new String(data, chars.name());
262
                } catch (java.io.UnsupportedEncodingException e) {
263
                        throw new UnsupportedEncodingException(
264
                                        e);
265
                }
266

    
267
        }
268

    
269
        public void setFieldValue(int rowIndex, int fieldId, Object obj) throws UnsupportedEncodingException, WriteException {
270
                try{
271
                        int fieldOffset = myHeader.getFieldDescription(fieldId).myFieldDataAddress;
272
                        String str = fieldString(obj, fieldId);
273
                        byte[] data = new byte[myHeader.getFieldLength(fieldId)];
274
                        recordOffset = (myHeader.getRecordLength() * rowIndex)
275
                                        + myHeader.getHeaderLength() + 1;
276

    
277
                        ByteBuffer aux = ByteBuffer.wrap(data);
278
                        aux.put(str.getBytes(chars.name()));
279
//                        raf.seek(recordOffset + fieldOffset);
280
//                        raf.writeBytes(str);
281
                        aux.flip();
282
//                        int numBytesWritten = channel.write(aux, recordOffset + fieldOffset);
283
                        channel.write(aux, recordOffset + fieldOffset);
284
                        //channel.force(true);
285
                }catch (java.io.UnsupportedEncodingException e) {
286
                        throw new UnsupportedEncodingException(e);
287
                }catch (IOException e) {
288
                        throw new WriteException("DBF",e);
289
                }
290

    
291
        }
292

    
293

    
294
        /**
295
         * Retrieve the name of the given column.
296
         *
297
         * @param inIndex
298
         *            DOCUMENT ME!
299
         *
300
         * @return DOCUMENT ME!
301
         */
302
        public String getFieldName(int inIndex) {
303
                return myHeader.getFieldName(inIndex).trim();
304
        }
305

    
306
        /**
307
         * Retrieve the type of the given column.
308
         *
309
         * @param inIndex
310
         *            DOCUMENT ME!
311
         *
312
         * @return DOCUMENT ME!
313
         */
314
        public char getFieldType(int inIndex) {
315
                return myHeader.getFieldType(inIndex);
316
        }
317

    
318
        /**
319
         * Retrieve the length of the given column.
320
         *
321
         * @param inIndex
322
         *            DOCUMENT ME!
323
         *
324
         * @return DOCUMENT ME!
325
         */
326
        public int getFieldLength(int inIndex) {
327
                return myHeader.getFieldLength(inIndex);
328
        }
329

    
330
        /*
331
         * Retrieve the value of the given column as string.
332
         *
333
         * @param idField DOCUMENT ME! @param idRecord DOCUMENT ME!
334
         *
335
         * @return DOCUMENT ME!
336
         *
337
         * public Object getFieldValue(int idField, long idRecord) throws
338
         * IOException { Object[] tmpReg = getRecord(idRecord); return
339
         * tmpReg[idField]; }
340
         */
341
        /*
342
         * DOCUMENT ME!
343
         *
344
         * @param idField DOCUMENT ME! @param idRecord DOCUMENT ME!
345
         *
346
         * @return DOCUMENT ME!
347
         *
348
         * public double getFieldValueAsDouble(int idField, int idRecord) throws
349
         * IOException { Object[] tmpReg = getRecord(idRecord); return (double)
350
         * Double.parseDouble(tmpReg[idField].toString()); }
351
         */
352

    
353
        /**
354
         * Retrieve the location of the decimal point.
355
         *
356
         * @param inIndex
357
         *            DOCUMENT ME!
358
         *
359
         * @return DOCUMENT ME!
360
         */
361
        public int getFieldDecimalLength(int inIndex) {
362
                return myHeader.getFieldDecimalCount(inIndex);
363
        }
364

    
365
        /**
366
         * read the DBF file into memory.
367
         *
368
         * @param file
369
         *            DOCUMENT ME!
370
         * @throws FileNotFoundException
371
         * @throws UnsupportedVersionException
372
         * @throws IOException
373
         *
374
         * @throws IOException
375
         *             DOCUMENT ME!
376
         */
377
        public void open() throws FileNotFoundException,
378
                        UnsupportedVersionException, IOException {
379
                /*
380
                 * 01h DOS USA code page 437 02h DOS Multilingual code page 850 03h
381
                 * Windows ANSI code page 1252 04h Standard Macintosh 64h EE MS-DOS code
382
                 * page 852 65h Nordic MS-DOS code page 865 66h Russian MS-DOS code page
383
                 * 866 67h Icelandic MS-DOS 68h Kamenicky (Czech) MS-DOS 69h Mazovia
384
                 * (Polish) MS-DOS 6Ah Greek MS-DOS (437G) 6Bh Turkish MS-DOS 96h
385
                 * Russian Macintosh 97h Eastern European Macintosh 98h Greek Macintosh
386
                 * C8h Windows EE code page 1250 C9h Russian Windows CAh Turkish Windows
387
                 * CBh Greek Windows
388
                 */
389
                if (!file.exists()) {
390
                        throw new FileNotFoundException(file);
391
                }
392
//                if (file.canWrite()) {
393
//                        try {
394
//                                raf = new RandomAccessFile(file, "rw");
395
//                                mode = FileChannel.MapMode.READ_WRITE;
396
//                        } catch (java.io.FileNotFoundException e) {
397
//                                raf = new RandomAccessFile(file, "r");
398
//                                mode = FileChannel.MapMode.READ_ONLY;
399
//                        }
400
//                } else {
401
                        raf = new RandomAccessFile(file, "r");
402
                        mode = FileChannel.MapMode.READ_ONLY;
403
//                }
404
                channel = raf.getChannel();
405

    
406
                // buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0,
407
                // channel.size());
408
                buffer = new BigByteBuffer2(channel, mode);
409

    
410
                // create the header to contain the header information.
411
                myHeader = new DbaseFileHeader();
412
                myHeader.readHeader(buffer);
413
                switch (myHeader.getLanguageID()) {
414
                case 0x01:
415
                        chars = Charset.forName("US-ASCII");
416
                        break;
417
                case 0x02:
418
                        chars = Charset.forName("ISO-8859-1");
419
                        break;
420
                case 0x03:
421
                        chars = Charset.forName("windows-1252");
422
                        break;
423
                case 0x04:
424
                        chars = Charset.forName("mac");
425
                        break;
426
                case 0x64:
427
                        chars = Charset.forName("ISO-8859-1");
428
                        break;
429
                case 0x65:
430
                        chars = Charset.forName("ISO-8859-1");
431
                        break;
432
                case 0x66:
433
                        chars = Charset.forName("ISO-8859-1");
434
                        break;
435
                case 0x67:
436
                        chars = Charset.forName("ISO-8859-1");
437
                        break;
438
                case 0x68:
439
                        chars = Charset.forName("greek");
440
                        break;
441
                case 0x69:
442
                        chars = Charset.forName("ISO-8859-1");
443
                        break;
444
                case 0x6A:
445
                        chars = Charset.forName("greek");
446
                        break;
447
                case 0x6B:
448
                        chars = Charset.forName("ISO-8859-1");
449
                        break;
450

    
451
                default:
452
                        chars = Charset.forName("ISO-8859-1");
453
                }
454
                bytesCachedRecord = new byte[myHeader.getRecordLength()];
455
                this.isOpen = true;
456
        }
457

    
458
        /**
459
         * Removes all data from the dataset
460
         * @throws CloseException
461
         *
462
         * @throws IOException
463
         *             DOCUMENT ME!
464
         */
465
        public void close() throws CloseException {
466
                try{
467
                raf.close();
468
                channel.close();
469
                buffer = null;
470
                posActual=-1;
471
                }catch (Exception e) {
472
                        throw new CloseException("DBF",e);
473
                }
474
                this.isOpen = false;
475
        }
476

    
477
        public FileChannel getWriteChannel() {
478
                return channel;
479
        }
480

    
481
        private String fieldString(Object obj, final int col) {
482
                String o;
483
                final int fieldLen = myHeader.getFieldLength(col);
484
                switch (myHeader.getFieldType(col)) {
485
                case 'C':
486
                case 'c':
487
                        o = formatter.getFieldString(fieldLen, (obj == null) ? NULL_STRING
488
                                        : ((String) obj));
489
                        break;
490
                case 'L':
491
                case 'l':
492
                        o = (obj == null) ? "F"
493
                                        : ((Boolean) obj).booleanValue() == true ? "T" : "F";
494
                        break;
495
                case 'M':
496
                case 'G':
497
                        o = formatter.getFieldString(fieldLen, (obj == null) ? NULL_STRING
498
                                        : ((String) obj));
499
                        break;
500
                case 'N':
501
                case 'n':
502
                case 'F':
503
                case 'f':
504
                        Number number = null;
505
                        if (obj == null) {
506
                                number = NULL_NUMBER;
507
                        } else {
508
                                Number gVal = (Number) obj;
509
                                number = new Double(gVal.doubleValue());
510
                        }
511
                        o = formatter.getFieldString(fieldLen, myHeader
512
                                        .getFieldDecimalCount(col), number);
513
                        break;
514
                case 'D':
515
                case 'd':
516
                        if (obj == null) {
517
                                o = NULL_DATE;
518
                        } else {
519
                                o = formatter.getFieldString(((Date) obj));
520
                        }
521
                        break;
522
                default:
523
                        throw new RuntimeException("Unknown type "
524
                                        + myHeader.getFieldType(col));
525
                }
526

    
527
                return o;
528
        }
529

    
530
        public boolean isOpen() {
531
                return this.isOpen;
532
        }
533

    
534
}