Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.file / org.gvsig.fmap.dal.file.dbf / src / main / java / org / gvsig / fmap / dal / store / dbf / utils / DbaseFile.java @ 40435

History | View | Annotate | Download (12.9 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
import org.gvsig.utils.bigfile.BigByteBuffer2;
29

    
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
    
37
    public static final int MAX_FIELD_NAME_LENGTH = 11;
38
    
39
        // Header information for the DBase File
40
        private DbaseFileHeader myHeader;
41

    
42
        private File file;
43

    
44
        private RandomAccessFile raf;
45

    
46
        private FileChannel channel;
47

    
48
        private BigByteBuffer2 buffer;
49

    
50
        private FileChannel.MapMode mode;
51

    
52
        private FieldFormatter formatter = new FieldFormatter();
53

    
54
        private long posActual = -1;
55

    
56
        private int recordOffset;
57

    
58
        private ByteBuffer cachedRecord = null;
59

    
60
        private byte[] bytesCachedRecord = null;
61

    
62
        private final Number NULL_NUMBER = new Integer(0);
63

    
64
        private final String NULL_STRING = "";
65

    
66
        private final String NULL_DATE = "        ";
67

    
68
        private Charset chars = null;
69
        private Charset charsOriginal;
70

    
71
        private boolean isOpen = false;
72

    
73

    
74
        /** Utility for formatting Dbase fields. */
75
        public static class FieldFormatter {
76
                private StringBuffer buffer = new StringBuffer(255);
77

    
78
                private NumberFormat numFormat = NumberFormat
79
                                .getNumberInstance(Locale.US);
80

    
81
                private Calendar calendar = Calendar.getInstance(Locale.US);
82

    
83
                private String emtpyString;
84

    
85
                private static final int MAXCHARS = 255;
86

    
87
                public FieldFormatter() {
88
                        // Avoid grouping on number format
89
                        numFormat.setGroupingUsed(false);
90

    
91
                        // build a 255 white spaces string
92
                        StringBuffer sb = new StringBuffer(MAXCHARS);
93
                        sb.setLength(MAXCHARS);
94
                        for (int i = 0; i < MAXCHARS; i++) {
95
                                sb.setCharAt(i, ' ');
96
                        }
97

    
98
                        emtpyString = sb.toString();
99
                }
100

    
101
                public String getFieldString(int size, String s) {
102
                        buffer.replace(0, size, emtpyString);
103
                        buffer.setLength(size);
104

    
105
                        if (s != null) {
106
                                buffer.replace(0, size, s);
107
                                if (s.length() <= size) {
108
                                        for (int i = s.length(); i < size; i++) {
109
                                                buffer.append(' ');
110
                                        }
111
                                }
112
                        }
113

    
114
                        buffer.setLength(size);
115
                        return buffer.toString();
116
                }
117

    
118
                public String getFieldString(Date d) {
119

    
120
                        if (d != null) {
121
                                buffer.delete(0, buffer.length());
122

    
123
                                calendar.setTime(d);
124
                                int year = calendar.get(Calendar.YEAR);
125
                                int month = calendar.get(Calendar.MONTH) + 1; // returns 0
126
                                                                                                                                // based month?
127
                                int day = calendar.get(Calendar.DAY_OF_MONTH);
128

    
129
                                if (year < 1000) {
130
                                        if (year >= 100) {
131
                                                buffer.append("0");
132
                                        } else if (year >= 10) {
133
                                                buffer.append("00");
134
                                        } else {
135
                                                buffer.append("000");
136
                                        }
137
                                }
138
                                buffer.append(year);
139

    
140
                                if (month < 10) {
141
                                        buffer.append("0");
142
                                }
143
                                buffer.append(month);
144

    
145
                                if (day < 10) {
146
                                        buffer.append("0");
147
                                }
148
                                buffer.append(day);
149
                        } else {
150
                                buffer.setLength(8);
151
                                buffer.replace(0, 8, emtpyString);
152
                        }
153

    
154
                        buffer.setLength(8);
155
                        return buffer.toString();
156
                }
157

    
158
                public String getFieldString(int size, int decimalPlaces, Number n) {
159
                        buffer.delete(0, buffer.length());
160

    
161
                        if (n != null) {
162
                                numFormat.setMaximumFractionDigits(decimalPlaces);
163
                                numFormat.setMinimumFractionDigits(decimalPlaces);
164
                                numFormat.format(n, buffer, new FieldPosition(
165
                                                NumberFormat.INTEGER_FIELD));
166
                        }
167

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

    
180
        public DbaseFile(File afile){
181
                this(afile, null);
182
        }
183

    
184
        public DbaseFile(File afile, Charset chars) {
185
                this.file = afile;
186
                this.chars = chars;
187
        }
188

    
189
        public byte getCodePage() {
190
                return myHeader.getLanguageID();
191
        }
192

    
193
        // Retrieve number of records in the DbaseFile
194
        public int getRecordCount() {
195
                return myHeader.getNumRecords();
196
        }
197

    
198
        /**
199
         * DOCUMENT ME!
200
         *
201
         * @return DOCUMENT ME!
202
         */
203
        public int getFieldCount() {
204
                return myHeader.getNumFields();
205
        }
206

    
207
        /**
208
         * DOCUMENT ME!
209
         *
210
         * @param rowIndex
211
         *            DOCUMENT ME!
212
         * @param fieldId
213
         *            DOCUMENT ME!
214
         *
215
         * @return DOCUMENT ME!
216
         */
217
        public boolean getBooleanFieldValue(int rowIndex, int fieldId) {
218
                int recordOffset = (myHeader.getRecordLength() * rowIndex)
219
                                + myHeader.getHeaderLength() + 1;
220

    
221
                // Se calcula el offset del campo
222
                int fieldOffset = 0;
223

    
224
                for (int i = 0; i < (fieldId - 1); i++) {
225
                        fieldOffset += myHeader.getFieldLength(i);
226
                }
227

    
228
                buffer.position(recordOffset + fieldOffset);
229

    
230
                char bool = (char) buffer.get();
231

    
232
                return ((bool == 't') || (bool == 'T') || (bool == 'Y') || (bool == 'y'));
233
        }
234

    
235
        /**
236
         * DOCUMENT ME!
237
         *
238
         * @param rowIndex
239
         *            DOCUMENT ME!
240
         * @param fieldId
241
         *            DOCUMENT ME!
242
         *
243
         * @return DOCUMENT ME!
244
         * @throws UnsupportedEncodingException
245
         */
246
        public String getStringFieldValue(int rowIndex, int fieldId)
247
                        throws UnsupportedEncodingException {
248
                int fieldOffset = myHeader.getFieldDescription(fieldId).myFieldDataAddress;
249
                byte[] data = new byte[myHeader.getFieldLength(fieldId)];
250
                if (rowIndex != posActual) {
251
                        recordOffset = (myHeader.getRecordLength() * rowIndex)
252
                                        + myHeader.getHeaderLength() + 1;
253

    
254
                        /*
255
                         * System.err.println("getStringFieldValue: rowIndex = " +
256
                         * rowIndex); System.err.println("recordOffset = " + recordOffset + "
257
                         * fieldOffset=" + fieldOffset);
258
                         */
259

    
260
                        buffer.position(recordOffset);
261
                        buffer.get(bytesCachedRecord);
262
                        cachedRecord = ByteBuffer.wrap(bytesCachedRecord);
263
                        posActual = rowIndex;
264

    
265
                }
266
                cachedRecord.position(fieldOffset);
267
                cachedRecord.get(data);
268

    
269
                try {
270
                        return new String(data, chars.name());
271
                } catch (java.io.UnsupportedEncodingException e) {
272
                        throw new UnsupportedEncodingException(
273
                                        e);
274
                }
275

    
276
        }
277

    
278
        public void setFieldValue(int rowIndex, int fieldId, Object obj) throws UnsupportedEncodingException, WriteException {
279
                try{
280
                        int fieldOffset = myHeader.getFieldDescription(fieldId).myFieldDataAddress;
281
                        String str = fieldString(obj, fieldId);
282
                        byte[] data = new byte[myHeader.getFieldLength(fieldId)];
283
                        recordOffset = (myHeader.getRecordLength() * rowIndex)
284
                                        + myHeader.getHeaderLength() + 1;
285

    
286
                        ByteBuffer aux = ByteBuffer.wrap(data);
287
                        aux.put(str.getBytes(chars.name()));
288
//                        raf.seek(recordOffset + fieldOffset);
289
//                        raf.writeBytes(str);
290
                        aux.flip();
291
//                        int numBytesWritten = channel.write(aux, recordOffset + fieldOffset);
292
                        channel.write(aux, recordOffset + fieldOffset);
293
                        //channel.force(true);
294
                }catch (java.io.UnsupportedEncodingException e) {
295
                        throw new UnsupportedEncodingException(e);
296
                }catch (IOException e) {
297
                        throw new WriteException("DBF",e);
298
                }
299

    
300
        }
301

    
302

    
303
        /**
304
         * Retrieve the name of the given column.
305
         *
306
         * @param inIndex
307
         *            DOCUMENT ME!
308
         *
309
         * @return DOCUMENT ME!
310
         */
311
        public String getFieldName(int inIndex) {
312
                return myHeader.getFieldName(inIndex).trim();
313
        }
314

    
315
        /**
316
         * Retrieve the type of the given column.
317
         *
318
         * @param inIndex
319
         *            DOCUMENT ME!
320
         *
321
         * @return DOCUMENT ME!
322
         */
323
        public char getFieldType(int inIndex) {
324
                return myHeader.getFieldType(inIndex);
325
        }
326

    
327
        /**
328
         * Retrieve the length of the given column.
329
         *
330
         * @param inIndex
331
         *            DOCUMENT ME!
332
         *
333
         * @return DOCUMENT ME!
334
         */
335
        public int getFieldLength(int inIndex) {
336
                return myHeader.getFieldLength(inIndex);
337
        }
338

    
339
        /*
340
         * Retrieve the value of the given column as string.
341
         *
342
         * @param idField DOCUMENT ME! @param idRecord DOCUMENT ME!
343
         *
344
         * @return DOCUMENT ME!
345
         *
346
         * public Object getFieldValue(int idField, long idRecord) throws
347
         * IOException { Object[] tmpReg = getRecord(idRecord); return
348
         * tmpReg[idField]; }
349
         */
350
        /*
351
         * DOCUMENT ME!
352
         *
353
         * @param idField DOCUMENT ME! @param idRecord DOCUMENT ME!
354
         *
355
         * @return DOCUMENT ME!
356
         *
357
         * public double getFieldValueAsDouble(int idField, int idRecord) throws
358
         * IOException { Object[] tmpReg = getRecord(idRecord); return (double)
359
         * Double.parseDouble(tmpReg[idField].toString()); }
360
         */
361

    
362
        /**
363
         * Retrieve the location of the decimal point.
364
         *
365
         * @param inIndex
366
         *            DOCUMENT ME!
367
         *
368
         * @return DOCUMENT ME!
369
         */
370
        public int getFieldDecimalLength(int inIndex) {
371
                return myHeader.getFieldDecimalCount(inIndex);
372
        }
373

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

    
415
                // buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0,
416
                // channel.size());
417
                buffer = new BigByteBuffer2(channel, mode);
418

    
419
                // create the header to contain the header information.
420
                myHeader = new DbaseFileHeader();
421
                if (chars == null) {
422
                        myHeader.readHeader(buffer, null);
423
                } else {
424
                        myHeader.readHeader(buffer, chars.name());
425
                }
426
                charsOriginal = Charset.forName(myHeader.mappingEncoding(myHeader.getCharsetName()));
427
                if (chars == null) {
428
                        chars = charsOriginal;
429
                }
430
                bytesCachedRecord = new byte[myHeader.getRecordLength()];
431
                this.isOpen = true;
432
        }
433

    
434
        /**
435
         * Removes all data from the dataset
436
         * @throws CloseException
437
         *
438
         * @throws IOException
439
         *             DOCUMENT ME!
440
         */
441
        public void close() throws CloseException {
442
                try{
443
                raf.close();
444
                channel.close();
445
                buffer = null;
446
                posActual=-1;
447
                myHeader = null;
448
                }catch (Exception e) {
449
                        throw new CloseException("DBF",e);
450
                }
451
                this.isOpen = false;
452
        }
453

    
454
        public FileChannel getWriteChannel() {
455
                return channel;
456
        }
457

    
458
        private String fieldString(Object obj, final int col) {
459
                String o;
460
                final int fieldLen = myHeader.getFieldLength(col);
461
                switch (myHeader.getFieldType(col)) {
462
                case 'C':
463
                case 'c':
464
                        o = formatter.getFieldString(fieldLen, (obj == null) ? NULL_STRING
465
                                        : ((String) obj));
466
                        break;
467
                case 'L':
468
                case 'l':
469
                        o = (obj == null) ? "F"
470
                                        : ((Boolean) obj).booleanValue() == true ? "T" : "F";
471
                        break;
472
                case 'M':
473
                case 'G':
474
                        o = formatter.getFieldString(fieldLen, (obj == null) ? NULL_STRING
475
                                        : ((String) obj));
476
                        break;
477
                case 'N':
478
                case 'n':
479
                case 'F':
480
                case 'f':
481
                        Number number = null;
482
                        if (obj == null) {
483
                                number = NULL_NUMBER;
484
                        } else {
485
                                Number gVal = (Number) obj;
486
                                number = new Double(gVal.doubleValue());
487
                        }
488
                        o = formatter.getFieldString(fieldLen, myHeader
489
                                        .getFieldDecimalCount(col), number);
490
                        break;
491
                case 'D':
492
                case 'd':
493
                        if (obj == null) {
494
                                o = NULL_DATE;
495
                        } else {
496
                                o = formatter.getFieldString(((Date) obj));
497
                        }
498
                        break;
499
                default:
500
                        throw new RuntimeException("Unknown type "
501
                                        + myHeader.getFieldType(col));
502
                }
503

    
504
                return o;
505
        }
506

    
507
        public boolean isOpen() {
508
                return this.isOpen;
509
        }
510

    
511
        public int getFieldIndex(String name) {
512
                return myHeader.getFieldIndex(name);
513
        }
514

    
515
        public Charset getCurrenCharset() {
516
                return chars;
517
        }
518

    
519
        public Charset getOriginalCharset() {
520
                return charsOriginal;
521
        }
522

    
523
        public void setCharset(Charset chars) {
524
                this.chars = chars;
525
        }
526

    
527
}