Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libFMap_dataFile / src / org / gvsig / fmap / data / feature / file / dbf / utils / DbaseFile.java @ 22373

History | View | Annotate | Download (12.7 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.data.feature.file.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.data.CloseException;
24
import org.gvsig.fmap.data.WriteException;
25
import org.gvsig.fmap.data.feature.UnsupportedEncodingException;
26
import org.gvsig.fmap.data.feature.UnsupportedVersionException;
27
import org.gvsig.fmap.data.feature.file.FileNotFoundException;
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 int 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

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

    
72
                private NumberFormat numFormat = NumberFormat
73
                                .getNumberInstance(Locale.US);
74

    
75
                private Calendar calendar = Calendar.getInstance(Locale.US);
76

    
77
                private String emtpyString;
78

    
79
                private static final int MAXCHARS = 255;
80

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

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

    
92
                        emtpyString = sb.toString();
93
                }
94

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

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

    
108
                        buffer.setLength(size);
109
                        return buffer.toString();
110
                }
111

    
112
                public String getFieldString(Date d) {
113

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

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

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

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

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

    
148
                        buffer.setLength(8);
149
                        return buffer.toString();
150
                }
151

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

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

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

    
174
        public DbaseFile(File afile){
175
                this.file= afile;
176
        }
177

    
178
        // Retrieve number of records in the DbaseFile
179
        public int getRecordCount() {
180
                return myHeader.getNumRecords();
181
        }
182

    
183
        /**
184
         * DOCUMENT ME!
185
         *
186
         * @return DOCUMENT ME!
187
         */
188
        public int getFieldCount() {
189
                return myHeader.getNumFields();
190
        }
191

    
192
        /**
193
         * DOCUMENT ME!
194
         *
195
         * @param rowIndex
196
         *            DOCUMENT ME!
197
         * @param fieldId
198
         *            DOCUMENT ME!
199
         *
200
         * @return DOCUMENT ME!
201
         */
202
        public boolean getBooleanFieldValue(int rowIndex, int fieldId) {
203
                int recordOffset = (myHeader.getRecordLength() * rowIndex)
204
                                + myHeader.getHeaderLength() + 1;
205

    
206
                // Se calcula el offset del campo
207
                int fieldOffset = 0;
208

    
209
                for (int i = 0; i < (fieldId - 1); i++) {
210
                        fieldOffset += myHeader.getFieldLength(i);
211
                }
212

    
213
                buffer.position(recordOffset + fieldOffset);
214

    
215
                char bool = (char) buffer.get();
216

    
217
                return ((bool == 't') || (bool == 'T') || (bool == 'Y') || (bool == 'y'));
218
        }
219

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

    
238
                        /*
239
                         * System.err.println("getStringFieldValue: rowIndex = " +
240
                         * rowIndex); System.err.println("recordOffset = " + recordOffset + "
241
                         * fieldOffset=" + fieldOffset);
242
                         */
243

    
244
                        buffer.position(recordOffset);
245
                        buffer.get(bytesCachedRecord);
246
                        cachedRecord = ByteBuffer.wrap(bytesCachedRecord);
247
                        posActual = rowIndex;
248

    
249
                }
250
                cachedRecord.position(fieldOffset);
251
                cachedRecord.get(data);
252

    
253
                try {
254
                        return new String(data, chars.name());
255
                } catch (java.io.UnsupportedEncodingException e) {
256
                        new UnsupportedEncodingException("DBF",e);
257
                }
258
                return null;
259

    
260
        }
261

    
262
        public void setFieldValue(int rowIndex, int fieldId, Object obj) throws UnsupportedEncodingException, WriteException {
263
                try{
264
                int fieldOffset = myHeader.getFieldDescription(fieldId).myFieldDataAddress;
265
                String str = fieldString(obj, fieldId);
266
                byte[] data = new byte[myHeader.getFieldLength(fieldId)];
267
                recordOffset = (myHeader.getRecordLength() * rowIndex)
268
                                + myHeader.getHeaderLength() + 1;
269

    
270
                ByteBuffer aux = ByteBuffer.wrap(data);
271
                aux.put(str.getBytes(chars.name()));
272
//                raf.seek(recordOffset + fieldOffset);
273
//                raf.writeBytes(str);
274
                aux.flip();
275
                int numBytesWritten = channel.write(aux, recordOffset + fieldOffset);
276
                //channel.force(true);
277
                }catch (java.io.UnsupportedEncodingException e) {
278
                        throw new UnsupportedEncodingException("DBF",e);
279
                }catch (IOException e) {
280
                        throw new WriteException("DBF",e);
281
                }
282

    
283
        }
284

    
285

    
286
        /**
287
         * Retrieve the name of the given column.
288
         *
289
         * @param inIndex
290
         *            DOCUMENT ME!
291
         *
292
         * @return DOCUMENT ME!
293
         */
294
        public String getFieldName(int inIndex) {
295
                return myHeader.getFieldName(inIndex).trim();
296
        }
297

    
298
        /**
299
         * Retrieve the type of the given column.
300
         *
301
         * @param inIndex
302
         *            DOCUMENT ME!
303
         *
304
         * @return DOCUMENT ME!
305
         */
306
        public char getFieldType(int inIndex) {
307
                return myHeader.getFieldType(inIndex);
308
        }
309

    
310
        /**
311
         * Retrieve the length of the given column.
312
         *
313
         * @param inIndex
314
         *            DOCUMENT ME!
315
         *
316
         * @return DOCUMENT ME!
317
         */
318
        public int getFieldLength(int inIndex) {
319
                return myHeader.getFieldLength(inIndex);
320
        }
321

    
322
        /*
323
         * Retrieve the value of the given column as string.
324
         *
325
         * @param idField DOCUMENT ME! @param idRecord DOCUMENT ME!
326
         *
327
         * @return DOCUMENT ME!
328
         *
329
         * public Object getFieldValue(int idField, long idRecord) throws
330
         * IOException { Object[] tmpReg = getRecord(idRecord); return
331
         * tmpReg[idField]; }
332
         */
333
        /*
334
         * DOCUMENT ME!
335
         *
336
         * @param idField DOCUMENT ME! @param idRecord DOCUMENT ME!
337
         *
338
         * @return DOCUMENT ME!
339
         *
340
         * public double getFieldValueAsDouble(int idField, int idRecord) throws
341
         * IOException { Object[] tmpReg = getRecord(idRecord); return (double)
342
         * Double.parseDouble(tmpReg[idField].toString()); }
343
         */
344

    
345
        /**
346
         * Retrieve the location of the decimal point.
347
         *
348
         * @param inIndex
349
         *            DOCUMENT ME!
350
         *
351
         * @return DOCUMENT ME!
352
         */
353
        public int getFieldDecimalLength(int inIndex) {
354
                return myHeader.getFieldDecimalCount(inIndex);
355
        }
356

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

    
394
                // buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0,
395
                // channel.size());
396
                buffer = new BigByteBuffer2(channel, mode);
397

    
398
                // create the header to contain the header information.
399
                myHeader = new DbaseFileHeader();
400
                myHeader.readHeader(buffer);
401
                switch (myHeader.getLanguageID()) {
402
                case 0x01:
403
                        chars = Charset.forName("US-ASCII");
404
                        break;
405
                case 0x02:
406
                        chars = Charset.forName("ISO-8859-1");
407
                        break;
408
                case 0x03:
409
                        chars = Charset.forName("windows-1252");
410
                        break;
411
                case 0x04:
412
                        chars = Charset.forName("mac");
413
                        break;
414
                case 0x64:
415
                        chars = Charset.forName("ISO-8859-1");
416
                        break;
417
                case 0x65:
418
                        chars = Charset.forName("ISO-8859-1");
419
                        break;
420
                case 0x66:
421
                        chars = Charset.forName("ISO-8859-1");
422
                        break;
423
                case 0x67:
424
                        chars = Charset.forName("ISO-8859-1");
425
                        break;
426
                case 0x68:
427
                        chars = Charset.forName("greek");
428
                        break;
429
                case 0x69:
430
                        chars = Charset.forName("ISO-8859-1");
431
                        break;
432
                case 0x6A:
433
                        chars = Charset.forName("greek");
434
                        break;
435
                case 0x6B:
436
                        chars = Charset.forName("ISO-8859-1");
437
                        break;
438

    
439
                default:
440
                        chars = Charset.forName("ISO-8859-1");
441
                }
442
                bytesCachedRecord = new byte[myHeader.getRecordLength()];
443
                }catch (IOException e) {
444
                        throw new FileNotFoundException("DBF",file.getAbsolutePath(),e);
445
                }
446
        }
447

    
448
        /**
449
         * Removes all data from the dataset
450
         * @throws CloseException
451
         *
452
         * @throws IOException
453
         *             DOCUMENT ME!
454
         */
455
        public void close() throws CloseException {
456
                try{
457
                raf.close();
458
                channel.close();
459
                buffer = null;
460
                posActual=-1;
461
                }catch (Exception e) {
462
                        throw new CloseException("DBF",e);
463
                }
464
        }
465

    
466
        public FileChannel getWriteChannel() {
467
                return channel;
468
        }
469

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

    
515
                return o;
516
        }
517

    
518
}