Statistics
| Revision:

root / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / drivers / shp / DbaseFileWriterNIO.java @ 8181

History | View | Annotate | Download (10.6 KB)

1 377 fjp
/*
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 1100 fjp
/* 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 377 fjp
package com.iver.cit.gvsig.fmap.drivers.shp;
64
65 6313 fjp
import java.io.IOException;
66
import java.nio.ByteBuffer;
67
import java.nio.MappedByteBuffer;
68
import java.nio.channels.FileChannel;
69
import java.nio.channels.WritableByteChannel;
70 6926 fjp
import java.nio.charset.Charset;
71 6313 fjp
import java.text.FieldPosition;
72
import java.text.NumberFormat;
73
import java.util.Calendar;
74
import java.util.Date;
75
import java.util.Locale;
76 377 fjp
77 2578 caballero
import com.hardcode.gdbms.engine.values.BooleanValue;
78
import com.hardcode.gdbms.engine.values.DateValue;
79 2581 fernando
import com.hardcode.gdbms.engine.values.NullValue;
80 4081 azabala
import com.hardcode.gdbms.engine.values.NumericValue;
81 2578 caballero
import com.hardcode.gdbms.engine.values.StringValue;
82
83 377 fjp
84
/** A DbaseFileReader is used to read a dbase III format file.
85
 * The general use of this class is:
86
 * <CODE><PRE>
87
 * DbaseFileHeader header = ...
88
 * WritableFileChannel out = new FileOutputStream("thefile.dbf").getChannel();
89
 * DbaseFileWriter w = new DbaseFileWriter(header,out);
90
 * while ( moreRecords ) {
91
 *   w.write( getMyRecord() );
92
 * }
93
 * w.close();
94
 * </PRE></CODE>
95
 * You must supply the <CODE>moreRecords</CODE> and <CODE>getMyRecord()</CODE>
96
 * logic...
97
 * @author Ian Schneider
98
 */
99
public class DbaseFileWriterNIO  {
100
101
  private DbaseFileHeaderNIO header;
102
  private DbaseFileWriterNIO.FieldFormatter formatter = new DbaseFileWriterNIO.FieldFormatter();
103
  WritableByteChannel channel;
104
  private ByteBuffer buffer;
105
  private final Number NULL_NUMBER = new Integer(0);
106
  private final String NULL_STRING = "";
107 3285 fjp
  private final String NULL_DATE = "        ";
108 377 fjp
109 6926 fjp
  // TODO: READ HEADER AND STABLIST THE RIGHT CHARSET
110
  private Charset charset = Charset.forName("ISO-8859-1");
111
112 377 fjp
  /** Create a DbaseFileWriter using the specified header and writing to the given
113
   * channel.
114
   * @param header The DbaseFileHeader to write.
115
   * @param out The Channel to write to.
116
   * @throws IOException If errors occur while initializing.
117
   */
118 3672 fjp
  public DbaseFileWriterNIO(DbaseFileHeaderNIO header,FileChannel out) throws IOException {
119 377 fjp
    header.writeHeader(out);
120
    this.header = header;
121
    this.channel = out;
122
123
    init();
124
  }
125
126
  private void init() throws IOException {
127
    buffer = ByteBuffer.allocateDirect(header.getRecordLength());
128
  }
129
130
  private void write() throws IOException {
131
    buffer.position(0);
132
    int r = buffer.remaining();
133
    while ( (r -= channel.write(buffer)) > 0) {
134
      ; // do nothing
135
    }
136
  }
137
138
139
  /** Write a single dbase record.
140
   * @param record The entries to write.
141
   * @throws IOException If IO error occurs.
142
   * @throws DbaseFileException If the entry doesn't comply to the header.
143
   */
144
  public void write(Object[] record) throws IOException{
145
  /*
146
    if (record.length != header.getNumFields()) {
147
      throw new DbaseFileException("Wrong number of fields " + record.length +
148
      " expected " +  header.getNumFields());
149
    }
150
    */
151
    buffer.position(0);
152
153
    // put the 'not-deleted' marker
154
    buffer.put( (byte) ' ');
155
156
    for (int i = 0; i < header.getNumFields(); i++) {
157
      String fieldString = fieldString(record[i], i);
158
//      if ( header.getFieldLength(i) != fieldString.getBytes().length) {
159
//          System.out.println(i + " : " + header.getFieldName(i));
160
//      }
161
162
163 6926 fjp
      buffer.put(fieldString.getBytes(charset.name()));
164 377 fjp
165
    }
166
167
168
    write();
169
  }
170
171
  private String fieldString(Object obj,final int col) {
172
    String o;
173
    final int fieldLen = header.getFieldLength(col);
174
    switch (header.getFieldType(col)) {
175
      case 'C':
176
      case 'c':
177
        o = formatter.getFieldString(
178
          fieldLen,
179 2581 fernando
          (obj instanceof NullValue)? NULL_STRING : ((StringValue) obj).getValue()
180 377 fjp
        );
181
        break;
182
      case 'L':
183
      case 'l':
184 2581 fernando
        o = (obj instanceof NullValue) ? "F" : ((BooleanValue)obj).getValue() == true ? "T" : "F";
185 377 fjp
        break;
186
      case 'M':
187
      case 'G':
188
        o = formatter.getFieldString(
189
          fieldLen,
190 2581 fernando
          (obj instanceof NullValue) ? NULL_STRING : ((StringValue) obj).getValue()
191 377 fjp
        );
192
        break;
193 1132 vcaballero
     /* case 'N':
194 377 fjp
      case 'n':
195
        // int?
196
        if (header.getFieldDecimalCount(col) == 0) {
197

198
          o = formatter.getFieldString(
199 1132 vcaballero
            fieldLen, 0, (Number) (obj == null ? NULL_NUMBER : Double.valueOf(obj.toString()))
200 377 fjp
          );
201
          break;
202 1132 vcaballero

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