Statistics
| Revision:

svn-gvsig-desktop / branches / simbologia / libraries / libFMap / src / com / iver / cit / gvsig / fmap / drivers / dbf / DbaseFile.java @ 10450

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: (5/15/2001 5:15:13 PM)
29
 */
30
public class DbaseFile {
31
        // Header information for the DBase File
32
        private DbaseFileHeader myHeader;
33

    
34
        private RandomAccessFile raf;
35

    
36
        private FileChannel channel;
37

    
38
        private BigByteBuffer2 buffer;
39

    
40
        private FileChannel.MapMode mode;
41

    
42
        private FieldFormatter formatter = new FieldFormatter();
43

    
44
        private int posActual = -1;
45

    
46
        private int recordOffset;
47

    
48
        private ByteBuffer cachedRecord = null;
49

    
50
        private byte[] bytesCachedRecord = null;
51

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

    
54
        private final String NULL_STRING = "";
55

    
56
        private final String NULL_DATE = "        ";
57

    
58
        private Charset chars;
59

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

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

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

    
69
                private String emtpyString;
70

    
71
                private static final int MAXCHARS = 255;
72

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

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

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

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

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

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

    
104
                public String getFieldString(Date d) {
105

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
201
                buffer.position(recordOffset + fieldOffset);
202

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

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

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

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

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

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

    
243
        }
244

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

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

    
261

    
262
        }
263

    
264

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

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

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

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

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

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

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

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

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

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

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

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

    
482
                return o;
483
        }
484

    
485
}