i have a clients.dat file with client info in it. i have gone through it to find the record i want to delete, used PushBackBuffer to unread the one i want top delete, skipped that bit and carried on reading the rest and writing it to clients.tmp.

after i have gone through the file and written the undeleted ones to clients.tmp, i want to delete the clients.dat and rename clients.tmp to clients.dat. have got everything right, except the deleting bit. i can't delete the original. i even tried deleteOnExit(), but that only works on the .tmp file.

i initially decided to use a class that handles the connections to the file (like i do with my database applications), but decided that for this i'll need to open the file and read/write, then close my streams again, because files are stupid and not as cool as databases.

i know i'm doing something stupid (because recently i've been making a ton of n00b-like errors and things), so i'm asking you guys for help.

i've attached the code for the FileHandler class which does the writing, deleting and updating of records in the file. if it's something REALLY obvious, then please feel free to hurl abuse at me.

thanks.

Attachments
package data.clients;

import data.files.FileHandler;

/*
* Class used to create a <code>Client</code> object that contains all the info about a client 
* that was read from a file or is to be written to a file.
*
*/
public class Client
{
    protected String id;
    protected String name;
    protected String address;
    protected String city;
    protected String code;
    protected String telephone;
    protected String vatNo;
	
	protected int[] fieldSizes = { 12,45,60,30,8,15,20 };
	public static int clientSize = 208;
	
	public static final int ID_FIELD = 1;
	public static final int NAME_FIELD = 2;
	public static final int ADDRESS_FIELD = 3;
	public static final int CITY_FIELD = 4;
	public static final int CODE_FIELD = 5;
	public static final int TELEPHONE_FIELD = 6;
	public static final int VATNO_FIELD = 7;
	
	

    /**
     * Constructs a new <code>Client</code> object with the given <code>String</code> values.
     *
     * @param   nm      the name of the company
     * @param   add     the address
     * @param   c       the city
     * @param   cd      the code
     * @param   tel     the telephone number
     * @param   vat     the VAT number
     */
    public Client( String nm, String add, String c, String cd, String tel, String vat )
    {
		data.files.FileHandler handler = new data.files.FileHandler();
		
		id = "" + handler.getNextID();
		handler.closeStreams();
        name = nm.toUpperCase();
        address = add.toUpperCase();
        city = c.toUpperCase();
        code = cd.toUpperCase();
        telephone = tel.toUpperCase();
        vatNo = vat.toUpperCase();
		
		boolean b = addWhiteSpace();
		
		String str = toString();
    }

    /**
     * Constructs a <code>Client</code> object with the values in the array 
     *
     * @param   data    a <code>String</code> array containing the values to be used
     */
    public Client( String[] data )
    {
		data.files.FileHandler handler = new data.files.FileHandler();
		
		if ( data[0].equals( "" ) )
		{
			id = "" + handler.getNextID();
			handler.closeStreams();
		}
		else
		{
			id = data[0];
		}
		
        name = data[1].toUpperCase();
        address = data[2].toUpperCase();
        city = data[3].toUpperCase();
        code = data[4].toUpperCase();
        telephone = data[5].toUpperCase();
        vatNo = data[6].toUpperCase();
		boolean b = this.addWhiteSpace();
		
		String str = toString();
    }
	
//	public Client( byte[] bytes )
//	{
//		
//	}

	/**
     * Sets the ID of the <code>Client</code> object to the new value.
     *
     *
     * @param	i	The new value for the ID of the <code>Client</code> object.
     */
    public void setID( int i )
    {
        id = "" + i;
    }

    /**
     * Returns the ID of the <code>Client</code> object as a <code>String</code> object.
     *
     * 
     * @return	<code>String</code> containing the name for the object.
     */
    public int getID()
    {
		String str = id.trim();
		return Integer.parseInt( str );
    }
	
    /**
     * Method setName. Sets the name of the <code>Client</code> object to the new value.
     *
     *
     * @param	str	The new value for the name of the <code>Client</code> object.
     */
    public void setName( String str )
    {
        name = str;
    }

    /**
     * Method getName. Returns the name of the <code>Client</code> object.
     *
     * 
     * @return	<code>String</code> containing the name for the object.
     */
    public String getName()
    {
            return name;
    }

    /**
     * Method setAddress. Sets the address of the <code>Client</code> object to the new value.
     *
     *
     * @param	str	The new value for the address of the <code>Client</code> object.
     */
    public void setAddress( String str )
    {
        address = str;
    }

    /**
     * Method getAddress. Returns the address of the <code>Client</code> object.
     *
     *
     * @return	<code>String</code> containing the address for the object.
     */
    public String getAddress()
    {
        return address;
    }

    /**
     * Method setCity. Sets the city of the <code>Client</code> object to the new value.
     *
     *
     * @param	str	The new value for the city of the <code>Client</code> object.
     */
    public void setCity( String str )
    {
        city = str;
    }

    /**
     * Method getCity. Returns the city of the <code>Client</code> object.
     *
     *
     * @return	<code>String</code> containing the city for the object.
     */
    public String getCity()
    {
        return city;
    }

    /**
     * Method setCode. Sets the code of the <code>Client</code> object to the new value.
     *
     *
     * @param	str	The new value for the code of the <code>Client</code> object.
     */
    public void setCode( String str )
    {
        code = str;
    }

    /**
     * Method getCode. Returns the code of the <code>Client</code> object.
     *
     *
     * @return	<code>String</code> containing the code for the object.
     */
    public String getCode()
    {
        return code;
    }

    /**
     * Method setTel. Sets the telephone number of the <code>Client</code> object to the new value.
     *
     *
     * @param	str	The new value for the telephone number of the <code>Client</code> object.
     */
    public void setTel( String str )
    {
        telephone = str;
    }

    /**
     * Method getTel. Returns the telephone number of the <code>Client</code> object.
     *
     *
     * @return	<code>String</code> containing the telephone number for the object.
     */
    public String getTel()
    {
        return telephone;
    }

    /**
     * Method setVatNo. Sets the vat number of the <code>Client</code> object to the new value.
     *
     *
     * @param	str	The new value for the vat number of the <code>Client</code> object.
     */
    public void setVatNo( String str )
    {
        vatNo = str;
    }

    /**
     * Method getVatNo. Returns the vat number of the <code>Client</code> object.
     *
     *
     * @return	<code>String</code> containing the vat number for the object.
     */
    public String getVatNo()
    {
        return vatNo;
    }
    
    /**
     * Tests whether the <code>Client</code> object contains the specified string in the
     * <code>name</code> field.
     *
     * @param   str the <code>String</code> to be used for testing.
     * @return	<code>true</code> if the <code>Client</code> contains the specified string 
     *          in the <code>name</code> field, otherwise <code>false</code>
     */
    public boolean hasName( String str )
    {
        return name.contains( str );
    }
    
    /**
     * Tests whether the <code>Client</code> object contains the specified string in the
     * <code>address</code> field.
     *
     * @param   str the <code>String</code> to be used for testing.
     * @return	<code>true</code> if the <code>Client</code> contains the specified string 
     *          in the <code>address</code> field, otherwise <code>false</code>
     */
    public boolean hasAddress( String str )
    {
        return address.contains( str );
    }
    
    /**
     * Tests whether the <code>Client</code> object contains the specified string in the
     * <code>city</code> field.
     *
     * @param   str the <code>String</code> to be used for testing.
     * @return	<code>true</code> if the <code>Client</code> contains the specified string 
     *          in the <code>city</code> field, otherwise <code>false</code>
     */
    public boolean hasCity( String str )
    {
        return city.contains( str );
    }
    
    /**
     * Tests whether the <code>Client</code> object contains the specified string in the
     * <code>code</code> field.
     *
     * @param   str the <code>String</code> to be used for testing.
     * @return	<code>true</code> if the <code>Client</code> contains the specified string 
     *          in the <code>code</code> field, otherwise <code>false</code>
     */
    public boolean hasCode( String str )
    {
        return code.contains( str );
    }
    
    /**
     * Tests whether the <code>Client</code> object contains the specified string in the
     * <code>telephone</code> field.
     *
     * @param   str the <code>String</code> to be used for testing.
     * @return	<code>true</code> if the <code>Client</code> contains the specified string 
     *          in the <code>telephone</code> field, otherwise <code>false</code>
     */
    public boolean hasTelephone( String str )
    {
        return telephone.contains( str );
    }
    
    /**
     * Tests whether the <code>Client</code> object contains the specified string in the
     * <code>vatNo</code> field.
     *
     * @param   str the <code>String</code> to be used for testing.
     * @return	<code>true</code> if the <code>Client</code> contains the specified string 
     *          in the <code>vatNo</code> field, otherwise <code>false</code>
     */
    public boolean hasVatNo( String str )
    {
        return vatNo.contains( str );
    }

    /**
     * Method toString
     *
     *
     * @return	A <code>String</code> representation of a <code>Client</code> object, including delimiters
     */
    public String toString()
    {
        return id + FileHandler.FIELD_DELIMITER + name + FileHandler.FIELD_DELIMITER + address + 
               FileHandler.FIELD_DELIMITER + city + FileHandler.FIELD_DELIMITER + code + FileHandler.FIELD_DELIMITER +
               telephone + FileHandler.FIELD_DELIMITER + vatNo;
    }

    public String[] toStringArray()
    {
        String[] strArr = new String[7];

        strArr[0] = id;
        strArr[1] = name;
        strArr[2] = address;
        strArr[3] = city;
        strArr[4] = code;
        strArr[5] = telephone;
        strArr[6] = vatNo;

        return strArr;
    }
	
	protected boolean addWhiteSpace()
	{
		Strin
package	data.files;

import data.clients.Client;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class FileHandler
{
	protected java.io.DataOutputStream output;
	protected java.io.DataInputStream input;
	protected RecordFile record;

	public FileHandler()
	{
		try
		{
			record = new RecordFile( "C:/datafiles/", "clients.dat" );
			input =	new	java.io.DataInputStream( record.getInputStream() );
			output = new java.io.DataOutputStream( record.getOutputStream() );
		}
		catch( data.files.NotFileException nfe )
		{
			nfe.printStackTrace();
		}
		catch( IOException ioe )
		{
			ioe.printStackTrace();
		}
		
	}

	/**
	 * Writes the <code>Client</code> object to	the	file
	 *
	 * @param	c	Writes the <code>Client</code> to the file.
	 * @return	returns <code>true</code> if successfully written to file, otherwise <code>false</code>.
	 */
	public boolean writeToFile(	Client c )
	{
		boolean written = false;
		try
		{
			c.setID( getNextID() );
			byte[] bytes = c.toString().getBytes();
			output.write( bytes );
			output.flush();
			written = true;
		}
		catch( IOException ioe )
		{
			System.out.println(	"IOException in	FileHandler.java writeToFile( Client c )" );
			ioe.printStackTrace();
		}
		return written;
	}

	/**
	 * Updates the file	with the details provided
	 *
	 *
	 * @param	id	an int value with the id of the record to be updated.
	 * @param	c	a <code>Client</code> object that will be writen to the file to update the old record
	 * @return	returns <code>true</code> if record was updated, otherwise <code>false</code>.
	 */
	public boolean updateRecord( int id, Client	c )
	{
		boolean	updated	= false;
		
		java.io.File tempFile = new java.io.File("c:/datafiles/clients.tmp");
		try
		{
			tempFile.createNewFile();
			java.io.DataInputStream tempInput = new java.io.DataInputStream( new java.io.FileInputStream( tempFile ) );
			java.io.DataOutputStream tempOutput = new java.io.DataOutputStream( new java.io.FileOutputStream( tempFile ) );
			java.io.PushbackInputStream pushBack = new java.io.PushbackInputStream( input, 512 );
			
			int numOfRecords = input.readInt();
			tempOutput.writeInt( numOfRecords );
			
			byte[] bytes = new byte[Client.clientSize];
			
			while ( pushBack.read(bytes) != -1 )
			{
				Client cl = new Client( bytes );
				if ( cl.getID() == id )
				{
					pushBack.unread( bytes );
					pushBack.skip( Client.clientSize );
					tempOutput.write( cl.toString().getBytes() );
					updated = true;
				}
				else
				{
					tempOutput.write( bytes );
				}
			}
			
			tempOutput.flush();
		}
		catch (IOException ioe)
		{
			ioe.printStackTrace();
		}
		
		
		boolean fileDeleted = false;
		
		if ( updated )
		{
			fileDeleted = record.deleteDataFile();
		}
			
		boolean renamed = false;
		
		if ( fileDeleted )
		{
			renamed = tempFile.renameTo( new java.io.File( "c:/datafiles/clients.dat" ) );
		}
		else
		{
			tempFile.delete();
		}
		
		return ( fileDeleted && renamed );
	}	

	/**
	 * Method findRecord
	 *
	 *
	 * @param	field	the <code>int</code> indicating which field to search. See data.clients.Client for
	 *					field variables.
	 * @param	search	The <code>String</code> with the value that will be searched for in the file.
	 *
	 * @return	A <code>Client</code> object found in the search. <code>null</code> if nothing found.
	 *
	 */
	public Client[]	findRecord(	int	field, String search )
	{
		java.util.Vector<Client> clientVector =	new	java.util.Vector<Client>();
		byte[] bytes = new byte[208];
		
		try
		{
			input.skipBytes( 4 );
			while (	( input.read( bytes	) )	!= 0 )
			{
				Client cl = new Client( bytes );
				
				boolean b = false;
				
				switch (field){
					case 1 : int i = cl.getID();
							 int tempInt = Integer.parseInt( search );
							 b = ( i == tempInt );
							 break;
					case 2 : b = cl.hasName( search );
							 break;
					case 3 : b = cl.hasAddress( search );
							 break;
					case 4 : b = cl.hasCity( search );
							 break;
					case 5 : b = cl.hasCode( search );
							 break;
					case 6 : b = cl.hasTelephone( search );
							 break;
					case 7 : b = cl.hasVatNo(search);
							 break;
				}
				
				if ( b )
					clientVector.add( cl );
			}
		}
		catch (	IOException	ioe )
		{
			System.out.println(	"IOException in	FileHandler.java findRecord( int field,	String search )" );
			ioe.printStackTrace();
		}
		int	sz = clientVector.size();
		if ( sz	== 0 )
		{
			return null;
		}
		Client[] clientArr = new Client[sz];
		clientVector.toArray(clientArr );
		
		return clientArr;
	}
	
	public boolean deleteRecord( int id )
	{
		boolean deleted = false;
		boolean found = false;
		boolean fileDeleted = false;
		
		java.io.File tempFile = new java.io.File("c:/datafiles/clients.tmp");
		
		try
		{
			tempFile.createNewFile();
			java.io.DataInputStream tempInput = new java.io.DataInputStream( new java.io.FileInputStream( tempFile ) );
			java.io.DataOutputStream tempOutput = new java.io.DataOutputStream( new java.io.FileOutputStream( tempFile ) );
			java.io.PushbackInputStream pushBack = new java.io.PushbackInputStream( input, 512 );
			
			int numOfRecords = input.readInt();
			numOfRecords--;
			tempOutput.writeInt( numOfRecords );
			
			byte[] bytes = new byte[Client.clientSize];
			
			while ( pushBack.read(bytes) != -1 )
			{
				Client cl = new Client( bytes );
				if ( cl.getID() == id )
				{
					pushBack.unread( bytes );
					pushBack.skip( Client.clientSize );
				}
				else
				{
					found = true;
					tempOutput.write( bytes );
				}
			}
			tempOutput.flush();
		}
		catch (IOException ioe)
		{
			ioe.printStackTrace();
		}
		
		long tempLength = tempFile.length();
		long fileLength = record.getFileLength();
		
		if ( ( fileLength - tempLength ) == Client.clientSize )
			deleted = true;
		
		if ( deleted )
			fileDeleted = record.deleteDataFile();
		else
			tempFile.delete();
		
		boolean renamed = false;
		
		if ( fileDeleted )
		{
			renamed = tempFile.renameTo( new java.io.File( "c:/datafiles/clients.dat" ) );
		}
		
		return ( deleted && renamed );
	}
	
	public int getNextID()
	{
		int numOfRecords = 0;
		
		try
		{
			numOfRecords = input.readInt();
			numOfRecords++;
		}
		catch( java.io.EOFException eof )
		{
			numOfRecords++;
		}
		catch( IOException ioe )
		{
			ioe.printStackTrace();
		}
		return numOfRecords;
	}
	
	public void	closeStreams()
	{
		try
		{
			output.flush();
			input.close();
			output.close();
		}
		catch( java.io.IOException ioe )
		{
			ioe.printStackTrace();
		}
	}
}

nevermind, i figured it out.

solution:

instead of creating the streams to the file in the constructor, i now create the streams in the methods when they're called and as soon as i am done, i close them and the file now deletes without me begging/swearing.

any ideas as to why that makes so much of a difference? the stream objects are still global variables, but now they're just being assigned values in the methods when they're called. to me that makes very little difference, because the closing of the streams still happen in the exact same place.

anyway, feel free to call me a n00b when you answer.

thanks again.

This question has already been answered. Start a new discussion instead.