Utility #Java code for cleanup before file creation

Por alguna extraña razón una de las funcionalidades más demandadas en la mayoría de los desarrollos de aplicaciones de software es la generación de reportes.

Independientemente del formato que se requiera, casi siempre esto se traduce en la construcción y guardado de algún archivo.

En mi experiencia, uno de los errores más observados en la realización de estas tareas es el omitir el correspondiente proceso de limpieza previa.

En este artículo, les comparto la manera de implementar una utilería en código Java que nos proporciona la funcionalidad requerida para dicho proceso.

Preparando la URI desde parámetros configurados en un archivo properties

Para comenzar, haremos un archivo reportes.properties en donde colocaremos la definición de los parámetros con los cuales armaremos la URI del recurso en cuestión.

report.docx.path=c://Temp//
report.docx.filename=reportDocx
report.docx.ext=.docx

En nuestra clase utilitaria habremos de definir las constantes necesarias para recuperar los valores de nuestro Properties:

	/** Constant REPORT_DOCX_EXT_KEY. */
	private static final String REPORT_DOCX_EXT_KEY = "report.docx.ext";

	/** Constant REPORT_DOCX_FILENAME_KEY. */
	private static final String REPORT_DOCX_FILENAME_KEY = "report.docx.filename";

	/** Constant REPORT_DOCX_PATH_KEY. */
	private static final String REPORT_DOCX_PATH_KEY = "report.docx.path";

Y una constante adicional que usaremos para nuestros mensajes de logging:

	/** Constant EL_ARCHIVO. */
	private static final String EL_ARCHIVO = "El archivo [";

Con una sencilla implementación donde concatenamos los valores recuperados del Properties podremos preparar la URI con la cual apuntaremos a nuestro recurso.

	/**
	 * Prepare URI.
	 *
	 * @return the string
	 */
	public static String prepareURI() {

		PropertiesFactory pf = new PropertiesFactory();
		Properties p = pf.getReportProperties();

		StringBuilder uri = new StringBuilder(p.getProperty(REPORT_DOCX_PATH_KEY));
		uri.append(p.getProperty(REPORT_DOCX_FILENAME_KEY)).append("_")
				.append(DateUtils.getDateStr(new Date(), DateUtils.DATE_FORMAT_YYYY_MM_DD));
		uri.append(p.getProperty(REPORT_DOCX_EXT_KEY));
		return uri.toString();
	}

Un extra: DateUtils

Como habrán notado, en mi caso, he agregado la inclusión de un sufijo con la fecha en formato yyyy-MM-dd. Así que, a pesar de que no es parte de nuestro tema actual, les compartiré el código para que implementen en una clase DateUtils.

	/**  The Constant DATE_FORMAT yyyy-MM-dd. */
	public static final String DATE_FORMAT_YYYY_MM_DD = "yyyy-MM-dd";

    /** Constant EJECUTANDO_GET_DATE_STR. */
    private static final String EJECUTANDO_GET_DATE_STR = "Ejecutando getDateStr(";

    /**
	 * Gets the date str.
	 *
	 * @param fecha   the fecha
	 * @param formato the formato
	 * @return the date str
	 */
    public static String getDateStr(Date fecha, String formato) {
    	LOGGER.debug(EJECUTANDO_GET_DATE_STR + fecha + ")");
		return DateUtils.getDateStr(fecha, formato, Locale.getDefault());
    }
    
        /**
	 * Gets the date str.
	 *
	 * @param fecha   the fecha
	 * @param formato the formato
	 * @param locale  the locale
	 * @return the date str
	 * @throws ParseException the parse exception
	 */
    public static Date getDateStr(String fecha, String formato, Locale locale) throws ParseException {
    	LOGGER.debug(EJECUTANDO_GET_DATE_STR + fecha + ")");
		SimpleDateFormat dateFormat = new SimpleDateFormat(
				StringUtils.isBlank(formato) ? DATE_FORMAT_DD_MM_YYYY : StringUtils.trim(formato), locale);
		return dateFormat.parse(StringUtils.isNotBlank(fecha)?fecha:StringUtils.EMPTY);
    }

Implementando cleanUp()

Contando ya con los elementos necesarios construyamos el método con el cual realizaremos la limpieza. El cual por supuesto, es mucho más que un simple delete().

No solo deberá realizar  las comprobaciones previas y la acción de borrado, sino que también debe incluir el manejo correspondiente para determinar de la mejor manera, en caso de que el proceso de limpieza falle cual fue el motivo por el cual no se alcanzó el objetivo.

/**
	 * Removes the file.
	 *
	 * @param exportFile the export file
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public static void cleanUp(String uri) throws NoSuchFileException, InterruptedIOException {
		boolean cleanDo = false;
		File exportFile = new File(uri);
		if (exportFile.exists()) {
			LOGGER.debug(EL_ARCHIVO + uri + "] ya existe, sera eliminado.");
			cleanDo = exportFile.delete();
			if (!cleanDo) {
				LOGGER.debug(EL_ARCHIVO + uri + "] existente no pudo ser eliminado. ");
				if (isFilelocked(exportFile)) {
					throw new InterruptedIOException(EL_ARCHIVO + uri + "] esta en uso");
				} else {
					throw new NoSuchFileException(exportFile.getAbsolutePath());
				}
			}
		} else {
			LOGGER.debug(EL_ARCHIVO + uri + "] no existe.");
		}
	}

El principal motivo por el cual suele fallar al querer realizar la limpieza es encontrarnos con la situación de que el archivo no pueda ser borrado por algún motivo. Por ejemplo, que el archivo se encuentre bloqueado.

Para realizar un apropiado manejo del error, validaremos que el archivo no se encuentre bloqueado, como es el caso que se presenta cuando se encuentra siendo utilizado por algún proceso. Ej: cuando el archivo ha sido abierto por algún aplicativo.

Validando si el recurso se encuentra bloqueado

	/**
	 * Checks if is filelocked.
	 *
	 * @param file the file
	 * @return true, if is filelocked
	 */
	public static boolean isFilelocked(File file) {
		boolean isLocked = false;
		try (FileOutputStream os = new FileOutputStream(file)) {
			os.write(0);
		} catch (FileNotFoundException e) {
			isLocked = file.exists();
		} catch (IOException ioe) {
			LOGGER.error("Ocurrio una IOException : " + ioe.getClass() + ":" + ioe.getMessage(), ioe);
			isLocked = true;
		}
		return isLocked;
	}

Espero te haya parecido útil este artículo

No olvides visitarme en mi perfil de GitHub: https://github.com/era5mx

………….

Quiero man.tener.me informado: Seguir en Twitter @eldavid_oficial https://twitter.com/eldavid_oficial

Regálame un ME GUSTA. Y si eres solidario, COMPARTE para que otros puedan aprovecharlo

Deja una respuesta

Por favor, inicia sesión con uno de estos métodos para publicar tu comentario:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.