Statistics
| Revision:

svn-gvsig-desktop / tags / Root_v061 / libraries / libFMap / src / com / iver / cit / gvsig / fmap / drivers / shp / DbaseFileWriterNIO.java @ 4812

History | View | Annotate | Download (10.2 KB)

1
/*
2
 *    Geotools - OpenSource mapping toolkit
3
 *    (C) 2002, Centre for Computational Geography
4
 *
5
 *    This library is free software; you can redistribute it and/or
6
 *    modify it under the terms of the GNU Lesser General Public
7
 *    License as published by the Free Software Foundation;
8
 *    version 2.1 of the License.
9
 *
10
 *    This library is distributed in the hope that it will be useful,
11
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 *    Lesser General Public License for more details.
14
 *
15
 *    You should have received a copy of the GNU Lesser General Public
16
 *    License along with this library; if not, write to the Free Software
17
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 *
19
 *    This file is based on an origional contained in the GISToolkit project:
20
 *    http://gistoolkit.sourceforge.net/
21
 *
22
 */
23
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
24
 *
25
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
26
 *
27
 * This program is free software; you can redistribute it and/or
28
 * modify it under the terms of the GNU General Public License
29
 * as published by the Free Software Foundation; either version 2
30
 * of the License, or (at your option) any later version.
31
 *
32
 * This program is distributed in the hope that it will be useful,
33
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
35
 * GNU General Public License for more details.
36
 *
37
 * You should have received a copy of the GNU General Public License
38
 * along with this program; if not, write to the Free Software
39
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
40
 *
41
 * For more information, contact:
42
 *
43
 *  Generalitat Valenciana
44
 *   Conselleria d'Infraestructures i Transport
45
 *   Av. Blasco Ib??ez, 50
46
 *   46010 VALENCIA
47
 *   SPAIN
48
 *
49
 *      +34 963862235
50
 *   gvsig@gva.es
51
 *      www.gvsig.gva.es
52
 *
53
 *    or
54
 *
55
 *   IVER T.I. S.A
56
 *   Salamanca 50
57
 *   46005 Valencia
58
 *   Spain
59
 *
60
 *   +34 963163400
61
 *   dac@iver.es
62
 */
63
package com.iver.cit.gvsig.fmap.drivers.shp;
64

    
65
import java.io.*;
66
import java.nio.channels.*;
67
import java.nio.*;
68
import java.text.*;
69
import org.geotools.resources.NIOUtilities;
70

    
71
import com.hardcode.gdbms.engine.values.BooleanValue;
72
import com.hardcode.gdbms.engine.values.DateValue;
73
import com.hardcode.gdbms.engine.values.DoubleValue;
74
import com.hardcode.gdbms.engine.values.NullValue;
75
import com.hardcode.gdbms.engine.values.NumericValue;
76
import com.hardcode.gdbms.engine.values.StringValue;
77

    
78
import java.util.*;
79

    
80

    
81
/** A DbaseFileReader is used to read a dbase III format file.
82
 * The general use of this class is:
83
 * <CODE><PRE>
84
 * DbaseFileHeader header = ...
85
 * WritableFileChannel out = new FileOutputStream("thefile.dbf").getChannel();
86
 * DbaseFileWriter w = new DbaseFileWriter(header,out);
87
 * while ( moreRecords ) {
88
 *   w.write( getMyRecord() );
89
 * }
90
 * w.close();
91
 * </PRE></CODE>
92
 * You must supply the <CODE>moreRecords</CODE> and <CODE>getMyRecord()</CODE>
93
 * logic...
94
 * @author Ian Schneider
95
 */
96
public class DbaseFileWriterNIO  {
97
  
98
  private DbaseFileHeaderNIO header;
99
  private DbaseFileWriterNIO.FieldFormatter formatter = new DbaseFileWriterNIO.FieldFormatter();
100
  WritableByteChannel channel;
101
  private ByteBuffer buffer;
102
  private final Number NULL_NUMBER = new Integer(0);
103
  private final String NULL_STRING = "";
104
  private final String NULL_DATE = "        ";
105
  
106
  /** Create a DbaseFileWriter using the specified header and writing to the given
107
   * channel.
108
   * @param header The DbaseFileHeader to write.
109
   * @param out The Channel to write to.
110
   * @throws IOException If errors occur while initializing.
111
   */
112
  public DbaseFileWriterNIO(DbaseFileHeaderNIO header,FileChannel out) throws IOException {
113
    header.writeHeader(out);
114
    this.header = header;
115
    this.channel = out;
116
    
117
    init();
118
  }
119
  
120
  private void init() throws IOException {
121
    buffer = ByteBuffer.allocateDirect(header.getRecordLength());
122
  }
123
  
124
  private void write() throws IOException {
125
    buffer.position(0);
126
    int r = buffer.remaining();
127
    while ( (r -= channel.write(buffer)) > 0) {
128
      ; // do nothing
129
    }
130
  }
131
  
132
  
133
  /** Write a single dbase record.
134
   * @param record The entries to write.
135
   * @throws IOException If IO error occurs.
136
   * @throws DbaseFileException If the entry doesn't comply to the header.
137
   */
138
  public void write(Object[] record) throws IOException{
139
  /*  
140
    if (record.length != header.getNumFields()) {
141
      throw new DbaseFileException("Wrong number of fields " + record.length +
142
      " expected " +  header.getNumFields());
143
    }
144
    */
145
    buffer.position(0);
146
    
147
    // put the 'not-deleted' marker
148
    buffer.put( (byte) ' ');
149
    
150
    for (int i = 0; i < header.getNumFields(); i++) {
151
      String fieldString = fieldString(record[i], i);
152
//      if ( header.getFieldLength(i) != fieldString.getBytes().length) {
153
//          System.out.println(i + " : " + header.getFieldName(i));
154
//      }
155
      
156
      
157
      buffer.put(fieldString.getBytes());
158
    
159
    }
160
    
161
    
162
    write();
163
  }
164
  
165
  private String fieldString(Object obj,final int col) {
166
    String o;
167
    final int fieldLen = header.getFieldLength(col);
168
    switch (header.getFieldType(col)) {
169
      case 'C':
170
      case 'c':
171
        o = formatter.getFieldString(
172
          fieldLen, 
173
          (obj instanceof NullValue)? NULL_STRING : ((StringValue) obj).getValue()
174
        );
175
        break;
176
      case 'L':
177
      case 'l':
178
        o = (obj instanceof NullValue) ? "F" : ((BooleanValue)obj).getValue() == true ? "T" : "F";
179
        break;
180
      case 'M':
181
      case 'G':
182
        o = formatter.getFieldString(
183
          fieldLen, 
184
          (obj instanceof NullValue) ? NULL_STRING : ((StringValue) obj).getValue()
185
        );
186
        break;
187
     /* case 'N':
188
      case 'n':
189
        // int?
190
        if (header.getFieldDecimalCount(col) == 0) {
191
            
192
          o = formatter.getFieldString(
193
            fieldLen, 0, (Number) (obj == null ? NULL_NUMBER : Double.valueOf(obj.toString()))
194
          );
195
          break;
196
       
197
         }
198
      */
199
      case 'N':
200
      case 'n':
201
      case 'F':
202
      case 'f':
203
            Number number = null;
204
            if(obj instanceof NullValue){
205
                    number = NULL_NUMBER;
206
            }else{
207
                    NumericValue gVal = (NumericValue) obj;
208
                    number = new Double(gVal.doubleValue());
209
            }
210
        o = formatter.getFieldString(fieldLen,
211
                        header.getFieldDecimalCount(col),
212
                                number);
213
        break;
214
      case 'D':
215
      case 'd':
216
          if (obj instanceof NullValue)
217
              o = NULL_DATE;
218
          else
219
              o = formatter.getFieldString(((DateValue)obj).getValue());
220
        break;
221
      default:
222
        throw new RuntimeException("Unknown type " + header.getFieldType(col));
223
    }
224

    
225
    return o;
226
  }
227
  
228
  /** Release resources associated with this writer.
229
   * <B>Highly recommended</B>
230
   * @throws IOException If errors occur.
231
   */
232
  public void close() throws IOException {
233
      // IANS - GEOT 193, bogus 0x00 written. According to dbf spec, optional
234
      // eof 0x1a marker is, well, optional. Since the original code wrote a
235
      // 0x00 (which is wrong anyway) lets just do away with this :)
236
      // - produced dbf works in OpenOffice and ArcExplorer java, so it must
237
      // be okay. 
238
//    buffer.position(0);
239
//    buffer.put((byte) 0).position(0).limit(1);
240
//    write();
241
    channel.close();
242
    if (buffer instanceof MappedByteBuffer) {
243
     // NIOUtilities.clean(buffer);
244
    }
245
    
246
    buffer = null;
247
    channel = null;
248
    formatter = null;
249
  }
250
  
251
  
252
  /** Utility for formatting Dbase fields. */
253
  public static class FieldFormatter {
254
    private StringBuffer buffer = new StringBuffer(255);
255
    private NumberFormat numFormat = NumberFormat.getNumberInstance(Locale.US);
256
    private Calendar calendar = Calendar.getInstance(Locale.US);
257
    private String emtpyString;
258
    private static final int MAXCHARS = 255;
259
    
260
    public FieldFormatter() {
261
      // Avoid grouping on number format
262
      numFormat.setGroupingUsed(false);
263
      
264
      // build a 255 white spaces string
265
      StringBuffer sb = new StringBuffer(MAXCHARS);
266
      sb.setLength(MAXCHARS);
267
      for(int i = 0; i < MAXCHARS; i++) {
268
        sb.setCharAt(i, ' ');
269
      }
270
      
271
      emtpyString = sb.toString();
272
    }
273
    
274
    public String getFieldString(int size, String s) {
275
      buffer.replace(0, size, emtpyString);
276
      buffer.setLength(size);
277
      
278
      if(s != null) {
279
        buffer.replace(0, size, s);
280
        if(s.length() <= size) {
281
          for(int i = s.length(); i < size; i++) {
282
            buffer.append(' ');
283
          }
284
        }
285
      }
286
      
287
      buffer.setLength(size);
288
      return buffer.toString();
289
    }
290
    
291
    public String getFieldString(Date d) {
292
      
293
      if(d != null) {
294
        buffer.delete(0, buffer.length());
295
        
296
        calendar.setTime(d);
297
        int year = calendar.get(Calendar.YEAR);
298
        int month = calendar.get(Calendar.MONTH) + 1;  // returns 0 based month?
299
        int day = calendar.get(Calendar.DAY_OF_MONTH);
300
        
301
        if(year < 1000) {
302
          if(year >= 100) {
303
            buffer.append("0");
304
          } else if(year >= 10) {
305
            buffer.append("00");
306
          } else {
307
            buffer.append("000");
308
          }
309
        }
310
        buffer.append(year);
311
        
312
        if(month < 10) {
313
          buffer.append("0");
314
        }
315
        buffer.append(month);
316
        
317
        if(day < 10) {
318
          buffer.append("0");
319
        }
320
        buffer.append(day);
321
      } else {
322
        buffer.setLength(8);
323
        buffer.replace(0, 8, emtpyString);
324
      }
325
      
326
      buffer.setLength(8);
327
      return buffer.toString();
328
    }
329
    
330
    public String getFieldString(int size, int decimalPlaces, Number n) {
331
      buffer.delete(0, buffer.length());
332
      
333
      if (n != null) {
334
        numFormat.setMaximumFractionDigits(decimalPlaces);
335
        numFormat.setMinimumFractionDigits(decimalPlaces);
336
        numFormat.format(n, buffer, new FieldPosition(NumberFormat.INTEGER_FIELD));
337
      }
338
      
339
      int diff = size - buffer.length();
340
      if (diff >= 0) {
341
          while (diff-- > 0) {
342
              buffer.insert(0, ' ');
343
          }
344
      } else {
345
          buffer.setLength(size);
346
      }
347
      return buffer.toString();
348
    }
349
  }
350
  
351
  
352
}